home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 April / enter-2004-04.iso / files / httrack-3.30.exe / {app} / src / htscore.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-10-11  |  110.3 KB  |  3,562 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: Main source                                            */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <time.h>
  41. #include <fcntl.h>
  42. #include <ctype.h>
  43.  
  44. /* File defs */
  45. #include "htscore.h"
  46.  
  47. /* specific definitions */
  48. #include "htsbase.h"
  49. #include "htsnet.h"
  50. #include "htsbauth.h"
  51. #include "htsmd5.h"
  52. #include "htsindex.h"
  53.  
  54. /* external modules */
  55. #include "htsmodules.h"
  56.  
  57. // htswrap_add
  58. #include "htswrap.h"
  59.  
  60. // parser
  61. #include "htsparse.h"
  62.  
  63. /* END specific definitions */
  64.  
  65.  
  66. /* HTML parsing */
  67. #if HTS_ANALYSTE
  68.  
  69. t_hts_htmlcheck_init    hts_htmlcheck_init = NULL;
  70. t_hts_htmlcheck_uninit  hts_htmlcheck_uninit = NULL;
  71. t_hts_htmlcheck_start   hts_htmlcheck_start = NULL;
  72. t_hts_htmlcheck_end     hts_htmlcheck_end = NULL;
  73. t_hts_htmlcheck_chopt   hts_htmlcheck_chopt = NULL;
  74. t_hts_htmlcheck         hts_htmlcheck = NULL;
  75. t_hts_htmlcheck_query   hts_htmlcheck_query = NULL;
  76. t_hts_htmlcheck_query2  hts_htmlcheck_query2 = NULL;
  77. t_hts_htmlcheck_query3  hts_htmlcheck_query3 = NULL;
  78. t_hts_htmlcheck_loop    hts_htmlcheck_loop = NULL;
  79. t_hts_htmlcheck_check   hts_htmlcheck_check = NULL;
  80. t_hts_htmlcheck_pause   hts_htmlcheck_pause = NULL;
  81. t_hts_htmlcheck_filesave       hts_htmlcheck_filesave = NULL;
  82. t_hts_htmlcheck_linkdetected   hts_htmlcheck_linkdetected = NULL;
  83. t_hts_htmlcheck_xfrstatus hts_htmlcheck_xfrstatus = NULL;
  84. t_hts_htmlcheck_savename  hts_htmlcheck_savename = NULL;
  85. t_hts_htmlcheck_sendhead  hts_htmlcheck_sendhead = NULL;
  86. t_hts_htmlcheck_receivehead  hts_htmlcheck_receivehead = NULL;
  87.  
  88.  
  89. char _hts_errmsg[1100]="";
  90. int _hts_in_html_parsing=0;
  91. int _hts_in_html_done=0;  // % done
  92. int _hts_in_html_poll=0;  // parsing
  93. int _hts_setpause=0;
  94. //httrackp* _hts_setopt=NULL;
  95. char** _hts_addurl=NULL;
  96.  
  97. /* external modules */
  98. extern int hts_parse_externals(htsmoduleStruct* str);
  99. extern void htspe_init(void);
  100.  
  101. //
  102. int _hts_cancel=0;
  103. #endif
  104.  
  105.  
  106.  
  107. int exit_xh;          /* quick exit (fatal error or interrupt) */
  108.  
  109. /* debug */
  110. #if DEBUG_SHOWTYPES
  111. char REG[32768]="\n";
  112. #endif
  113. #if NSDEBUG
  114. int nsocDEBUG=0;
  115. #endif
  116.  
  117. //
  118. #define _CLRSCR printf("\33[m\33[2J");
  119. #define _GOTOXY(X,Y) printf("\33[" X ";" Y "f");
  120.  
  121. #if DEBUG_CHECKINT
  122.  #define _CHECKINT_FAIL(a) printf("\n%s\n",a); fflush(stdout); exit(1);
  123.  #define _CHECKINT(obj_ptr,message) \
  124.    if (obj_ptr) {\
  125.      if (( * ((char*) (obj_ptr)) != 0) || ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0)) {\
  126.        char msg[1100];\
  127.        if (( * ((char*) (obj_ptr)) != 0) && ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0))\
  128.          sprintf(msg,"* PANIC: Integrity error (structure crushed)  in: %s",message);\
  129.        else if ( * ((char*) (obj_ptr)) != 0)\
  130.          sprintf(msg,"* PANIC: Integrity error (start of structure) in: %s",message);\
  131.        else\
  132.          sprintf(msg,"* PANIC: Integrity error (end of structure)   in: %s",message);\
  133.        _CHECKINT_FAIL(msg);\
  134.      }\
  135.    } else {\
  136.      char msg[1100];\
  137.      sprintf(msg,"* PANIC: NULL pointer in: %s",message);\
  138.      _CHECKINT_FAIL(msg);\
  139.    }
  140. #endif
  141.  
  142. #if DEBUG_HASH
  143.   // longest hash chain?
  144.   int longest_hash[3]={0,0,0},hashnumber=0;
  145. #endif
  146.  
  147. // demande d'interaction avec le shell
  148. #if HTS_ANALYSTE
  149. char HTbuff[2048];
  150. #endif
  151.  
  152.  
  153.  
  154. // DΘbut de httpmirror, routines annexes
  155.  
  156. // version 1 pour httpmirror
  157. // flusher si on doit lire peu α peu le fichier
  158. #define test_flush if (opt.flush) { fflush(opt.log); fflush(opt.errlog); }
  159.  
  160. // pour allΘger la syntaxe, des raccourcis sont crΘΘs
  161. #define urladr   (liens[ptr]->adr)
  162. #define urlfil   (liens[ptr]->fil)
  163. #define savename (liens[ptr]->sav)
  164. //#define level    (liens[ptr]->depth)
  165.  
  166. // au cas o∙ nous devons quitter rapidement xhttpmirror (plus de mΘmoire, etc)
  167. // note: partir de liens_max.. vers 0.. sinon erreur de violation de mΘmoire: les liens suivants
  168. // ne sont plus α nous.. agh! [dur celui-lα]
  169. #if HTS_ANALYSTE
  170. #define HTMLCHECK_UNINIT { \
  171. if ( (opt.debug>0) && (opt.log!=NULL) ) { \
  172. fspc(opt.log,"info"); fprintf(opt.log,"engine: end"LF); \
  173. } \
  174. hts_htmlcheck_end(); \
  175. }
  176. #else
  177.  #define HTMLCHECK_UNINIT 
  178. #endif
  179.  
  180. #define XH_extuninit do { \
  181.   int i; \
  182.   HTMLCHECK_UNINIT \
  183.   if (liens!=NULL) { \
  184.   for(i=lien_max-1;i>=0;i--) { \
  185.   if (liens[i]) { \
  186.   if (liens[i]->firstblock==1) { \
  187.   freet(liens[i]); \
  188.   liens[i]=NULL; \
  189.   } \
  190.   } \
  191.   } \
  192.   freet(liens); \
  193.   liens=NULL; \
  194.   } \
  195.   if (filters && filters[0]) { \
  196.   freet(filters[0]); filters[0]=NULL; \
  197.   } \
  198.   if (filters) { \
  199.   freet(filters); filters=NULL; \
  200.   } \
  201.   if (back) { \
  202.   int i; \
  203.   for(i=0;i<back_max;i++) { \
  204.   back_delete(&opt,back,i); \
  205.   } \
  206.   freet(back); back=NULL;  \
  207.   } \
  208.   checkrobots_free(&robots);\
  209.   if (cache.use) { freet(cache.use); cache.use=NULL; } \
  210.   if (cache.dat) { fclose(cache.dat); cache.dat=NULL; }  \
  211.   if (cache.ndx) { fclose(cache.ndx); cache.ndx=NULL; } \
  212.   if (cache.olddat) { fclose(cache.olddat); cache.olddat=NULL; } \
  213.   if (cache.lst) { fclose(cache.lst); cache.lst=NULL; } \
  214.   if (cache.txt) { fclose(cache.txt); cache.txt=NULL; } \
  215.   if (opt.log) fflush(opt.log); \
  216.   if (opt.errlog) fflush(opt.errlog);\
  217.   if (makestat_fp) { fclose(makestat_fp); makestat_fp=NULL; } \
  218.   if (maketrack_fp){ fclose(maketrack_fp); maketrack_fp=NULL; } \
  219.   if (opt.accept_cookie) cookie_save(opt.cookie,fconcat(opt.path_log,"cookies.txt")); \
  220.   if (makeindex_fp) { fclose(makeindex_fp); makeindex_fp=NULL; } \
  221.   if (cache_hashtable) { inthash_delete(&cache_hashtable); } \
  222.   if (template_header) { freet(template_header); template_header=NULL; } \
  223.   if (template_body)   { freet(template_body); template_body=NULL; } \
  224.   if (template_footer) { freet(template_footer); template_footer=NULL; } \
  225.   /*structcheck_init(-1);*/ \
  226. } while(0)
  227. #define XH_uninit do { XH_extuninit; if (r.adr) { freet(r.adr); r.adr=NULL; } } while(0)
  228.  
  229. // Enregistrement d'un lien:
  230. // on calcule la taille nΘcessaire: taille des 3 chaεnes α stocker (taille forcΘe paire, plus 2 octets de sΘcuritΘ)
  231. // puis on vΘrifie qu'on a assez de marge dans le buffer - sinon on en rΘalloue un autre
  232. // enfin on Θcrit α l'adresse courante du buffer, qu'on incrΘmente. on dΘcrΘmente la taille dispo d'autant ensuite
  233. // codebase: si non nul et si .class stockee on le note pour chemin primaire pour classes
  234. // FA,FS: former_adr et former_fil, lien original
  235. #if HTS_HASH
  236. #define liens_record_sav_len(A) 
  237. #else
  238. #define liens_record_sav_len(A) (A)->sav_len=strlen((A)->sav)
  239. #endif
  240.  
  241. #define liens_record(A,F,S,FA,FF,NORM) { \
  242. int notecode=0; \
  243. int lienurl_len=((sizeof(lien_url)+HTS_ALIGN-1)/HTS_ALIGN)*HTS_ALIGN,\
  244.   adr_len=strlen(A),\
  245.   fil_len=strlen(F),\
  246.   sav_len=strlen(S),\
  247.   cod_len=0,\
  248.   former_adr_len=strlen(FA),\
  249.   former_fil_len=strlen(FF); \
  250. if (former_adr_len>0) {\
  251.   former_adr_len=(former_adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  252.   former_fil_len=(former_fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  253. } else former_adr_len=former_fil_len=0;\
  254. if (strlen(F)>6) if (strnotempty(codebase)) if (strfield(F+strlen(F)-6,".class")) { notecode=1; \
  255. cod_len=strlen(codebase); cod_len=(cod_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; } \
  256. adr_len=(adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; fil_len=(fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; sav_len=(sav_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  257. if ((int) lien_size < (int) (adr_len+fil_len+sav_len+cod_len+former_adr_len+former_fil_len+lienurl_len)) { \
  258. lien_buffer=(char*) ((void*) calloct(add_tab_alloc,1)); \
  259. lien_size=add_tab_alloc; \
  260. if (lien_buffer!=NULL) { \
  261. liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=lienurl_len; lien_size-=lienurl_len; \
  262. liens[lien_tot]->firstblock=1; \
  263. } \
  264. } else { \
  265. liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=lienurl_len; lien_size-=lienurl_len; \
  266. liens[lien_tot]->firstblock=0; \
  267. } \
  268. if (liens[lien_tot]!=NULL) { \
  269. liens[lien_tot]->adr=lien_buffer; lien_buffer+=adr_len; lien_size-=adr_len; \
  270. liens[lien_tot]->fil=lien_buffer; lien_buffer+=fil_len; lien_size-=fil_len; \
  271. liens[lien_tot]->sav=lien_buffer; lien_buffer+=sav_len; lien_size-=sav_len; \
  272. liens[lien_tot]->cod=NULL; \
  273. if (notecode) { liens[lien_tot]->cod=lien_buffer; lien_buffer+=cod_len; lien_size-=cod_len; strcpybuff(liens[lien_tot]->cod,codebase); } \
  274. if (former_adr_len>0) {\
  275. liens[lien_tot]->former_adr=lien_buffer; lien_buffer+=former_adr_len; lien_size-=former_adr_len; \
  276. liens[lien_tot]->former_fil=lien_buffer; lien_buffer+=former_fil_len; lien_size-=former_fil_len; \
  277. strcpybuff(liens[lien_tot]->former_adr,FA); \
  278. strcpybuff(liens[lien_tot]->former_fil,FF); \
  279. }\
  280. strcpybuff(liens[lien_tot]->adr,A); \
  281. strcpybuff(liens[lien_tot]->fil,F); \
  282. strcpybuff(liens[lien_tot]->sav,S); \
  283. liens_record_sav_len(liens[lien_tot]); \
  284. hash_write(hashptr,lien_tot,NORM);  \
  285. } \
  286. }
  287.  
  288.  
  289. #define HT_INDEX_END do { \
  290. if (!makeindex_done) { \
  291. if (makeindex_fp) { \
  292.   char tempo[1024]; \
  293.   if (makeindex_links == 1) { \
  294.     sprintf(tempo,"<meta HTTP-EQUIV=\"Refresh\" CONTENT=\"0; URL=%s\">"CRLF,makeindex_firstlink); \
  295.   } else \
  296.     tempo[0]='\0'; \
  297.   fprintf(makeindex_fp,template_footer, \
  298.     "<!-- Mirror and index made by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->", \
  299.     tempo \
  300.     ); \
  301.   fflush(makeindex_fp); \
  302.   fclose(makeindex_fp);  /* α ne pas oublier sinon on passe une nuit blanche */  \
  303.   makeindex_fp=NULL; \
  304.   usercommand(&opt,0,NULL,fconcat(opt.path_html,"index.html"),"","");  \
  305. } \
  306. } \
  307. makeindex_done=1;    /* ok c'est fait */  \
  308. } while(0)
  309.  
  310.  
  311.  
  312.  
  313. // DΘbut de httpmirror, robot
  314. // url1 peut Ωtre multiple
  315. int httpmirror(char* url1,httrackp* ptropt) {
  316.   httrackp opt = *ptropt;      // structure d'options
  317.   char* primary=NULL;          // premiΦre page, contenant les liens α scanner
  318.   int lien_tot=0;              // nombre de liens pour le moment
  319.   lien_url** liens=NULL;       // les pointeurs sur les liens
  320.   hash_struct hash;            // systΦme de hachage, accΘlΦre la recherche dans les liens
  321.   hash_struct* hashptr = &hash;
  322.   t_cookie cookie;             // gestion des cookies
  323.   int lien_max=0;
  324.   int lien_size=0;        // octets restants dans buffer liens dispo
  325.   char* lien_buffer=NULL; // buffer liens actuel
  326.   int add_tab_alloc=256000;    // +256K de liens α chaque fois
  327.   //char* tab_alloc=NULL;
  328.   int ptr;             // pointeur actuel sur les liens
  329.   //
  330.   int numero_passe=0;  // deux passes pour html puis images
  331.   int back_max=0;      // fichiers qui peuvent Ωtre en local
  332.   lien_back* back=NULL; // backing en local
  333.   htsblk r;            // retour de certaines fonctions
  334.   TStamp lastime=0;    // pour affichage infos de tmp en tmp
  335.   // pour les stats, nombre de fichiers & octets Θcrits
  336.   LLint stat_fragment=0;  // pour la fragmentation
  337.   //TStamp istat_timestart;   // dΘpart pour calcul instantannΘ
  338.   //
  339.   TStamp last_info_shell=0;
  340.   int info_shell=0;
  341.   // filtres
  342.   char** filters = NULL;
  343.   //int filter_max=0;
  344.   int filptr=0;
  345.   //
  346.   int makeindex_done=0;  // lorsque l'index sera fait
  347.   FILE* makeindex_fp=NULL;
  348.   int makeindex_links=0;
  349.   char makeindex_firstlink[HTS_URLMAXSIZE*2];
  350.   // statistiques (mode #Z)
  351.   FILE* makestat_fp=NULL;    // fichier de stats taux transfert
  352.   FILE* maketrack_fp=NULL;   // idem pour le tracking
  353.   TStamp makestat_time=0;    // attente (secondes)
  354.   LLint makestat_total=0;    // repΦre du nombre d'octets transfΘrΘs depuis denriΦre stat
  355.   int makestat_lnk=0;        // idem, pour le nombre de liens
  356.   //
  357.   char codebase[HTS_URLMAXSIZE*2];  // base pour applet java
  358.   char base[HTS_URLMAXSIZE*2];      // base pour les autres fichiers
  359.   //
  360.   cache_back cache;
  361.   robots_wizard robots;    // gestion robots.txt
  362.   inthash cache_hashtable=NULL;
  363.   int cache_hash_size=0;
  364.   //
  365.   char *template_header=NULL,*template_body=NULL,*template_footer=NULL;
  366.   //
  367.   codebase[0]='\0'; base[0]='\0';
  368.   //
  369.   cookie.auth.next=NULL;
  370.   cookie.auth.auth[0]=cookie.auth.prefix[0]='\0';
  371.   //
  372.  
  373.   // noter heure actuelle de dΘpart en secondes
  374.   memset(&HTS_STAT, 0, sizeof(HTS_STAT));
  375.   HTS_STAT.stat_timestart=time_local();
  376.   //istat_timestart=stat_timestart;
  377.   HTS_STAT.istat_timestart[0]=HTS_STAT.istat_timestart[1]=mtime_local();
  378.   /* reset stats */
  379.   HTS_STAT.HTS_TOTAL_RECV=0;
  380.   HTS_STAT.istat_bytes[0]=HTS_STAT.istat_bytes[1]=0;
  381.   /*
  382.   if (opt.aff_progress)
  383.     lastime=HTS_STAT.stat_timestart;
  384.     */
  385.   if (opt.shell) {
  386.     last_info_shell=HTS_STAT.stat_timestart;
  387.   }
  388.   if ((opt.makestat) || (opt.maketrack)){
  389.     makestat_time=HTS_STAT.stat_timestart;
  390.   }
  391.   // initialiser compteur erreurs
  392.   fspc(NULL,NULL);
  393.  
  394.   // init external modules
  395.   htspe_init();
  396.  
  397.   // initialiser cookie
  398.   if (opt.accept_cookie) {
  399.     opt.cookie=&cookie;
  400.     cookie.max_len=30000;       // max len
  401.     strcpybuff(cookie.data,"");
  402.     // Charger cookies.txt par dΘfaut ou cookies.txt du miroir
  403.     cookie_load(opt.cookie,opt.path_log,"cookies.txt");
  404.     cookie_load(opt.cookie,"","cookies.txt");
  405.   } else
  406.     opt.cookie=NULL;
  407.  
  408.   // initialiser exit_xh
  409.   exit_xh=0;          // sortir prΘmaturΘment (var globale)
  410.  
  411.   // initialiser usercommand
  412.   usercommand(&opt,opt.sys_com_exec,opt.sys_com,"","","");
  413.  
  414.   // initialiser structcheck
  415.   // structcheck_init(1);
  416.  
  417.   // initialiser tableau options accessible par d'autres fonctions (signal)
  418.   hts_declareoptbuffer(&opt);
  419.  
  420.   // initialiser verif_backblue
  421.   verif_backblue(&opt,NULL);
  422.   verif_external(0,0);
  423.   verif_external(1,0);
  424.  
  425.   // et templates html
  426.   template_header=readfile_or(fconcat(opt.path_bin,"templates/index-header.html"),HTS_INDEX_HEADER);
  427.   template_body=readfile_or(fconcat(opt.path_bin,"templates/index-body.html"),HTS_INDEX_BODY);
  428.   template_footer=readfile_or(fconcat(opt.path_bin,"templates/index-footer.html"),HTS_INDEX_FOOTER);
  429.  
  430.   // initialiser mimedefs
  431.   get_userhttptype(1,opt.mimedefs,NULL);
  432.  
  433.   // Initialiser indexation
  434.   if (opt.kindex)
  435.     index_init(opt.path_html);
  436.  
  437.   // effacer bloc cache
  438.   memset(&cache, 0, sizeof(cache_back));
  439.   cache.type=opt.cache;  // cache?
  440.   cache.errlog=opt.errlog;  // err log?
  441.   cache.ptr_ant=cache.ptr_last=0;   // pointeur pour anticiper
  442.  
  443.   // initialiser hash cache
  444.   if (!cache_hash_size) 
  445.     cache_hash_size=HTS_HASH_SIZE;
  446.   cache_hashtable=inthash_new(cache_hash_size);
  447.   if (cache_hashtable==NULL) {
  448.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  449.     filters[0]=NULL; back_max=0;    // uniquement a cause du warning de XH_extuninit
  450.     XH_extuninit;
  451.     return 0;
  452.   }
  453.   cache.hashtable=(void*)cache_hashtable;      /* copy backcache hash */
  454.  
  455.   // initialiser cache DNS
  456.   _hts_lockdns(-999);
  457.   
  458.   // robots.txt
  459.   strcpybuff(robots.adr,"!");    // dummy
  460.   robots.token[0]='\0';
  461.   robots.next=NULL;          // suivant
  462.   opt.robotsptr = &robots;
  463.   
  464.   // effacer filters
  465.   opt.maxfilter = maximum(opt.maxfilter, 128);
  466.   if (filters_init(&filters, opt.maxfilter, 0) == 0) {
  467.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  468.     back_max=0;    // uniquement a cause du warning de XH_extuninit
  469.     XH_extuninit;
  470.     return 0;
  471.   }
  472.   opt.filters.filters=&filters;
  473.   //
  474.   opt.filters.filptr=&filptr;
  475.   //opt.filters.filter_max=&filter_max;
  476.   
  477.   // hash table
  478.   opt.hash = &hash;
  479.  
  480.   // tableau de pointeurs sur les liens
  481.   lien_max=maximum(opt.maxlink,32);
  482.   liens=(lien_url**) malloct(lien_max*sizeof(lien_url*));   // tableau de pointeurs sur les liens
  483.   if (liens==NULL) {
  484.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  485.     //XH_uninit;
  486.     return 0;
  487.   } else {
  488.     int i;
  489.     for(i=0;i<lien_max;i++) {
  490.       liens[i]=NULL;     
  491.     }
  492.   }
  493.   // initialiser ptr et lien_tot
  494.   ptr=0;
  495.   lien_tot=0;
  496. #if HTS_HASH
  497.   // initialiser hachage
  498.   {
  499.     int i;
  500.     for(i=0;i<HTS_HASH_SIZE;i++)
  501.       hash.hash[0][i]=hash.hash[1][i]=hash.hash[2][i] = -1;    // pas d'entrΘes
  502.     hash.liens = liens;
  503.     hash.max_lien=0;
  504.   }
  505. #endif
  506.  
  507.   
  508.   // copier adresse(s) dans liste des adresses
  509.   {
  510.     char *a=url1;
  511.     int primary_len=8192;
  512.     if (strnotempty(opt.filelist)) {
  513.       primary_len+=max(0,fsize(opt.filelist)*2);
  514.     }
  515.     primary_len+=strlen(url1)*2;
  516.  
  517.     // crΘation de la premiΦre page, qui contient les liens de base α scanner
  518.     // c'est plus propre et plus logique que d'entrer α la main les liens dans la pile
  519.     // on bΘnΘficie ainsi des vΘrifications et des tests du robot pour les liens "primaires"
  520.     primary=(char*) malloct(primary_len); 
  521.     if (primary) {
  522.       primary[0]='\0';
  523.     } else {
  524.       printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  525.       back_max=0;    // uniquement a cause du warning de XH_extuninit
  526.       XH_extuninit;
  527.       return 0;
  528.     }
  529.     
  530.     while(*a) {
  531.       int i;
  532.       int joker=0;
  533.  
  534.       // vΘrifier qu'il n'y a pas de * dans l'url
  535.       if (*a=='+')
  536.         joker=1;
  537.       else if (*a=='-')
  538.         joker=1;
  539.       
  540.       if (joker) {    // joker ou filters
  541.         //char* p;
  542.         char tempo[HTS_URLMAXSIZE*2];
  543.         int type; int plus=0;
  544.  
  545.         // noter joker (dans b)
  546.         if (*a=='+') {  // champ +
  547.           type=1; plus=1; a++;
  548.         } else if (*a=='-') {  // champ forbidden[]
  549.           type=0; a++;
  550.         } else {  // champ + avec joker sans doute
  551.           type=1;
  552.         }
  553.  
  554.         // recopier prochaine chaine (+ ou -)
  555.         i=0;
  556.         while((*a!=0) && (!isspace((unsigned char)*a))) { tempo[i++]=*a; a++; }  
  557.         tempo[i++]='\0';
  558.         while(isspace((unsigned char)*a)) { a++; }
  559.  
  560.         // sauter les + sans rien aprΦs..
  561.         if (strnotempty(tempo)) {
  562.           if ((plus==0) && (type==1)) {  // implicite: *www.edf.fr par exemple
  563.             if (tempo[strlen(tempo)-1]!='*') {
  564.               strcatbuff(tempo,"*");  // ajouter un *
  565.             }
  566.           }
  567.           if (type)
  568.             strcpybuff(filters[filptr],"+");
  569.           else
  570.             strcpybuff(filters[filptr],"-");
  571.           /*
  572.           if (strfield(tempo,"http://"))
  573.             strcatbuff(filters[filptr],tempo+7);        // ignorer http://
  574.           else if (strfield(tempo,"ftp://"))
  575.             strcatbuff(filters[filptr],tempo+6);        // ignorer ftp://
  576.           else
  577.           */
  578.           strcatbuff(filters[filptr],tempo);
  579.           filptr++;
  580.           
  581.           /* sanity check */
  582.           if (filptr + 1 >= opt.maxfilter) {
  583.             opt.maxfilter += HTS_FILTERSINC;
  584.             if (filters_init(&filters, opt.maxfilter, HTS_FILTERSINC) == 0) {
  585.               printf("PANIC! : Too many filters : >%d [%d]\n",filptr,__LINE__);
  586.               if (opt.errlog) {
  587.                 fprintf(opt.errlog,LF"Too many filters, giving up..(>%d)"LF,filptr);
  588.                 fprintf(opt.errlog,"To avoid that: use #F option for more filters (example: -#F5000)"LF);
  589.                 test_flush;
  590.               }
  591.               back_max=0;    // uniquement a cause du warning de XH_extuninit
  592.               XH_extuninit;
  593.               return 0;
  594.             }
  595.             //opt.filters.filters=filters;
  596.           }
  597.  
  598.         }
  599.         
  600.       } else {    // adresse normale
  601.         char url[HTS_URLMAXSIZE*2];
  602.         // prochaine adresse
  603.         i=0;
  604.         while((*a!=0) && (!isspace((unsigned char)*a))) { url[i++]=*a; a++; }  
  605.         while(isspace((unsigned char)*a)) { a++; }
  606.         url[i++]='\0';
  607.  
  608.         //strcatbuff(primary,"<PRIMARY=\"");
  609.         if (strstr(url,":/")==NULL)
  610.           strcatbuff(primary,"http://");
  611.         strcatbuff(primary,url);
  612.         //strcatbuff(primary,"\">");
  613.         strcatbuff(primary,"\n");
  614.       }
  615.     }  // while
  616.  
  617.     /* load URL file list */
  618.     /* OPTIMIZED for fast load */
  619.     if (strnotempty(opt.filelist)) {
  620.       char* filelist_buff=NULL;
  621.       INTsys filelist_sz=fsize(opt.filelist);
  622.       if (filelist_sz>0) {
  623.         FILE* fp=fopen(opt.filelist,"rb");
  624.         if (fp) {
  625.           filelist_buff=malloct(filelist_sz + 2);
  626.           if (filelist_buff) {
  627.             if ((INTsys)fread(filelist_buff,1,filelist_sz,fp) != filelist_sz) {
  628.               freet(filelist_buff);
  629.               filelist_buff=NULL;
  630.             } else {
  631.               *(filelist_buff + filelist_sz) = '\0';
  632.             }
  633.           }
  634.           fclose(fp);
  635.         }
  636.       }
  637.       
  638.       if (filelist_buff) {
  639.         int filelist_ptr=0;
  640.         int n=0;
  641.         char line[HTS_URLMAXSIZE*2];
  642.         char* primary_ptr = primary + strlen(primary);
  643.         while( filelist_ptr < filelist_sz ) {
  644.           int count=binput(filelist_buff+filelist_ptr,line,HTS_URLMAXSIZE);
  645.           filelist_ptr+=count;
  646.           if (count && line[0]) {
  647.             n++;
  648.             if (strstr(line,":/")==NULL) {
  649.               strcpybuff(primary_ptr, "http://");
  650.               primary_ptr += strlen(primary_ptr);
  651.             }
  652.             strcpybuff(primary_ptr, line);
  653.             primary_ptr += strlen(primary_ptr);
  654.             strcpybuff(primary_ptr, "\n");
  655.             primary_ptr += 1;
  656.           }
  657.         }
  658.         // fclose(fp);
  659.         if (opt.log!=NULL) {
  660.           fspc(opt.log,"info"); fprintf(opt.log,"%d links added from %s"LF,n,opt.filelist); test_flush;
  661.         }
  662.  
  663.         // Free buffer
  664.         freet(filelist_buff);
  665.       } else {
  666.         if (opt.errlog!=NULL) {
  667.           fspc(opt.errlog,"error"); fprintf(opt.errlog,"Could not include URL list: %s"LF,opt.filelist); test_flush;
  668.         }
  669.       }
  670.     }
  671.  
  672.  
  673.     // lien primaire
  674.     liens_record("primary","/primary",fslash(fconcat(opt.path_html,"index.html")),"","",opt.urlhack);
  675.     if (liens[lien_tot]==NULL) {  // erreur, pas de place rΘservΘe
  676.       printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  677.       if (opt.errlog) {
  678.         fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  679.         test_flush;
  680.       }
  681.       back_max=0;    // uniquement a cause du warning de XH_extuninit
  682.       XH_extuninit;    // dΘsallocation mΘmoire & buffers
  683.       return 0;
  684.     }    
  685.     liens[lien_tot]->testmode=0;          // pas mode test
  686.     liens[lien_tot]->link_import=0;       // pas mode import
  687.     liens[lien_tot]->depth=opt.depth+1;   // lien de prioritΘ maximale
  688.     liens[lien_tot]->pass2=0;             // 1Φre passe
  689.     liens[lien_tot]->retry=opt.retry;     // lien de prioritΘ maximale
  690.     liens[lien_tot]->premier=lien_tot;    // premier lien, objet-pΦre=objet              
  691.     liens[lien_tot]->precedent=lien_tot;  // lien prΘcΘdent
  692.     lien_tot++;  
  693.  
  694.     // Initialiser cache
  695.     {
  696.       int backupXFR = htsMemoryFastXfr;
  697. #if HTS_ANALYSTE
  698.       _hts_in_html_parsing=4;
  699. #endif
  700.       if (!hts_htmlcheck_loop(NULL,0,0,0,lien_tot,0,NULL)) {
  701.         exit_xh=1;  // exit requested
  702.       }
  703.       htsMemoryFastXfr = 1;               /* fast load */
  704.       cache_init(&cache,&opt);
  705.       htsMemoryFastXfr = backupXFR;
  706. #if HTS_ANALYSTE
  707.       _hts_in_html_parsing=0;
  708. #endif
  709.     }
  710.  
  711.   }
  712.   
  713. #if BDEBUG==3
  714.   {
  715.     int i;
  716.     for(i=0;i<lien_tot;i++) {
  717.       printf("%d>%s%s as %s\n",i,liens[i]->adr,liens[i]->fil,liens[i]->sav);
  718.     }
  719.     for(i=0;i<filptr;i++) {
  720.       printf("%d>filters=%s\n",i,filters[i]);
  721.     }
  722.   }
  723. #endif
  724.    
  725.   // backing
  726.   //soc_max=opt.maxsoc;
  727.   if (opt.maxsoc>0) {
  728. #if BDEBUG==2
  729.     _CLRSCR;
  730. #endif
  731.     // Nombre de fichiers HTML pouvant Ωtre prΘsents en mΘmoire de maniΦre simultannΘe
  732.     // On prΘvoit large: les fichiers HTML ne prennent que peu de place en mΘmoire, et les
  733.     // fichiers non html sont sauvΘs en direct sur disque.
  734.     // --> 1024 entrΘes + 32 entrΘes par socket en supplΘment
  735.     back_max=opt.maxsoc*32+1024;
  736.     //back_max=opt.maxsoc*8+32;
  737.     back=(lien_back*) calloct((back_max+1),sizeof(lien_back));
  738.     if (back==NULL) {
  739.       if (opt.errlog)
  740.         fprintf(opt.errlog,"Not enough memory, can not allocate %d bytes"LF,(int)((opt.maxsoc+1)*sizeof(lien_back)));
  741.       return 0;
  742.     } else {    // copier buffer-location & effacer
  743.       int i;
  744.       for(i=0;i<back_max;i++){
  745.         back[i].r.location=back[i].location_buffer;
  746.         back[i].status=-1;
  747.         back[i].r.soc=INVALID_SOCKET;
  748.       }
  749.     }
  750.   }
  751.  
  752.  
  753.   // flush
  754.   test_flush;
  755.  
  756.   // statistiques
  757.   if (opt.makestat) {
  758.     makestat_fp=fopen(fconcat(opt.path_log,"hts-stats.txt"),"wb");
  759.     if (makestat_fp != NULL) {
  760.       fprintf(makestat_fp,"HTTrack statistics report, every minutes"LF LF);
  761.     }
  762.   }
  763.  
  764.   // tracking -- dΘbuggage
  765.   if (opt.maketrack) {
  766.     maketrack_fp=fopen(fconcat(opt.path_log,"hts-track.txt"),"wb");
  767.     if (maketrack_fp != NULL) {
  768.       fprintf(maketrack_fp,"HTTrack tracking report, every minutes"LF LF);
  769.     }
  770.   }
  771.  
  772.   // on n'a pas de liens!! (exemple: httrack www.* impossible sans dΘpart..)
  773.   if (lien_tot<=0) {
  774.     if (opt.errlog) {
  775.       fprintf(opt.errlog,"Error! You MUST specify at least one complete URL, and not only wildcards!"LF);
  776.     }
  777.   }
  778.  
  779.  
  780.   // attendre une certaine heure..
  781.   if (opt.waittime>0) {
  782.     int rollover=0;
  783.     int ok=0;
  784.     {
  785.       TStamp tl=0;
  786.       time_t tt;
  787.       struct tm* A;
  788.       tt=time(NULL);
  789.       A=localtime(&tt);
  790.       tl+=A->tm_sec;
  791.       tl+=A->tm_min*60;
  792.       tl+=A->tm_hour*60*60;
  793.       if (tl>opt.waittime)  // attendre minuit
  794.         rollover=1;
  795.     }
  796.  
  797.     // attendre..
  798.     do {
  799.       TStamp tl=0;
  800.       time_t tt;
  801.       struct tm* A;
  802.       tt=time(NULL);
  803.       A=localtime(&tt);
  804.       tl+=A->tm_sec;
  805.       tl+=A->tm_min*60;
  806.       tl+=A->tm_hour*60*60;
  807.  
  808.       if (rollover) {
  809.         if (tl<=opt.waittime)
  810.           rollover=0;  // attendre heure
  811.       } else {
  812.         if (tl>opt.waittime)
  813.           ok=1;  // ok!
  814.       }
  815.       
  816. #if HTS_ANALYSTE
  817.       {  
  818.         int r;
  819.         if (rollover)
  820.           r=hts_htmlcheck_loop(back,back_max,0,0,lien_tot,(int) (opt.waittime-tl+24*3600),NULL);
  821.         else
  822.           r=hts_htmlcheck_loop(back,back_max,0,0,lien_tot,(int) (opt.waittime-tl),NULL);
  823.         if (!r) {
  824.           exit_xh=1;  // exit requested
  825.           ok=1;          
  826.         } else
  827.           Sleep(100);
  828.       }
  829. #endif
  830.     } while(!ok);    
  831.     
  832.     // note: recopie de plus haut
  833.     // noter heure actuelle de dΘpart en secondes
  834.     HTS_STAT.stat_timestart=time_local();
  835.     /*
  836.     if (opt.aff_progress)
  837.       lastime=HTS_STAT.stat_timestart;
  838.       */
  839.     if (opt.shell) {
  840.       last_info_shell=HTS_STAT.stat_timestart;
  841.     }
  842.     if ((opt.makestat) || (opt.maketrack)){
  843.       makestat_time=HTS_STAT.stat_timestart;
  844.     }
  845.  
  846.  
  847.   }  
  848.   /* Info for wrappers */
  849.   if ( (opt.debug>0) && (opt.log!=NULL) ) {
  850.     fspc(opt.log,"info"); fprintf(opt.log,"engine: start"LF);
  851.   }
  852. #if HTS_ANALYSTE
  853.   if (!hts_htmlcheck_start(&opt)) {
  854.     XH_extuninit;
  855.     return 1;
  856.   }
  857. #endif
  858.   
  859.  
  860.   // ------------------------------------------------------------
  861.  
  862.   // ------------------------------------------------------------
  863.   // Boucle gΘnΘrale de parcours des liens
  864.   // ------------------------------------------------------------
  865.   do {
  866.     int error=0;          // si error alors sauter
  867.     int store_errpage=0;  // c'est une erreur mais on enregistre le html
  868.     char loc[HTS_URLMAXSIZE*2];    // adresse de relocation
  869.  
  870.     // Ici on charge le fichier (html, gif..) en mΘmoire
  871.     // Les HTMLs sont traitΘs (si leur prioritΘ est suffisante)
  872.  
  873.     // effacer r
  874.     memset(&r, 0, sizeof(htsblk)); r.soc=INVALID_SOCKET;
  875.     r.location=loc;    // en cas d'erreur 3xx (moved)
  876.     // recopier proxy
  877.     memcpy(&(r.req.proxy), &opt.proxy, sizeof(opt.proxy));
  878.     // et user-agent
  879.     strcpybuff(r.req.user_agent,opt.user_agent);
  880.     r.req.user_agent_send=opt.user_agent_send;
  881.  
  882.     if (!error) {
  883.       
  884.       // Skip empty/invalid/done in background
  885.       if (liens[ptr]) {
  886.         while (  (liens[ptr]) && (
  887.                     ( ((urladr != NULL)?(urladr):(" "))[0]=='!') ||
  888.                     ( ((urlfil != NULL)?(urlfil):(" "))[0]=='\0') ||
  889.                     ( (liens[ptr]->pass2 == -1) )
  890.                  )
  891.                ) {  // sauter si lien annulΘ (ou fil vide)
  892.           if ((opt.debug>1) && (opt.log!=NULL)) {
  893.             fspc(opt.log,"debug"); fprintf(opt.log,"link #%d seems ready, skipping: %s%s.."LF,ptr,((urladr != NULL)?(urladr):(" ")),((urlfil != NULL)?(urlfil):(" ")));
  894.             test_flush;
  895.           }
  896.           ptr++;
  897.         }
  898.       }
  899.       if (liens[ptr]) {    // on a qq chose α rΘcupΘrer?
  900.  
  901.         if ( (opt.debug>1) && (opt.log!=NULL) ) {
  902.           fspc(opt.log,"debug"); fprintf(opt.log,"Wait get: %s%s"LF,urladr,urlfil);
  903.           test_flush;
  904. #if DEBUG_ROBOTS
  905.           if (strcmp(urlfil,"/robots.txt") == 0) {
  906.             printf("robots.txt detected\n");
  907.           }
  908. #endif
  909.         }    
  910.         // ------------------------------------------------------------
  911.         // DEBUT --RECUPERATION LIEN---
  912.         if (ptr==0) {              // premier lien α parcourir: lien primaire construit avant
  913.           r.adr=primary; primary=NULL;
  914.           r.statuscode=200;
  915.           r.size=strlen(r.adr);
  916.           r.soc=INVALID_SOCKET;
  917.           strcpybuff(r.contenttype,"text/html");
  918.         /*} else if (opt.maxsoc<=0) {   // fichiers 1 α 1 en attente (pas de backing)
  919.           // charger le fichier en mΘmoire tout bΩtement
  920.           r=xhttpget(urladr,urlfil);
  921.           //
  922.         */
  923.         } else {    // backing, multiples sockets
  924.           
  925.           
  926.           /*
  927.             **************************************
  928.             Get the next link, waiting for other files, handling external callbacks
  929.           */
  930.           {
  931.             char buff_err_msg[1024];
  932.             htsmoduleStruct str;
  933.             htsmoduleStructExtended stre;
  934.             buff_err_msg[0] = '\0';
  935.             memset(&str, 0, sizeof(str));
  936.             memset(&stre, 0, sizeof(stre));
  937.             /* */
  938.             str.err_msg = buff_err_msg;
  939.             str.filename = savename;
  940.             str.mime = r.contenttype;
  941.             str.url_host = urladr;
  942.             str.url_file = urlfil;
  943.             str.size = (int) r.size;
  944.             /* */
  945.             str.addLink = htsAddLink;
  946.             /* */
  947.             str.liens = liens;
  948.             str.opt = &opt;
  949.             str.back = back;
  950.             str.back_max = back_max;
  951.             str.cache = &cache;
  952.             str.hashptr = hashptr;
  953.             str.numero_passe = numero_passe;
  954.             str.add_tab_alloc = add_tab_alloc;
  955.             /* */
  956.             str.lien_tot_ = &lien_tot;
  957.             str.ptr_ = &ptr;
  958.             str.lien_size_ = &lien_size;
  959.             str.lien_buffer_ = &lien_buffer;
  960.             /* */
  961.             /* */
  962.             stre.r_ = &r;
  963.             /* */
  964.             stre.error_ = &error;
  965.             stre.exit_xh_ = &exit_xh;
  966.             stre.store_errpage_ = &store_errpage;
  967.             /* */
  968.             stre.base = base;
  969.             stre.codebase = codebase;
  970.             /* */
  971.             stre.filters_ = &filters;
  972.             stre.filptr_ = &filptr;
  973.             stre.robots_ = &robots;
  974.             stre.hash_ = &hash;
  975.             stre.lien_max_ = &lien_max;
  976.             /* */
  977.             stre.makeindex_done_ = &makeindex_done;
  978.             stre.makeindex_fp_ = &makeindex_fp;
  979.             stre.makeindex_links_ = &makeindex_links;
  980.             stre.makeindex_firstlink_ = makeindex_firstlink;
  981.             /* */
  982.             stre.template_header_ = template_header;
  983.             stre.template_body_ = template_body;
  984.             stre.template_footer_ = template_footer;
  985.             /* */
  986.             stre.stat_fragment_ = &stat_fragment;
  987.             stre.makestat_time = makestat_time;
  988.             stre.makestat_fp = makestat_fp;
  989.             stre.makestat_total_ = &makestat_total;
  990.             stre.makestat_lnk_ = &makestat_lnk;
  991.             stre.maketrack_fp = maketrack_fp;
  992.             /* FUNCTION DEPENDANT */
  993.             stre.loc_ = loc;
  994.             stre.last_info_shell_ = &last_info_shell;
  995.             stre.info_shell_ = &info_shell;
  996.  
  997.             /* Parse */
  998.             switch(hts_mirror_wait_for_next_file(&str, &stre)) {
  999.             case -1:
  1000.               XH_uninit;
  1001.               return -1;
  1002.               break;
  1003.             case 2:
  1004.               // Jump to 'continue'
  1005.               // This is one of the very very rare cases where goto
  1006.               // is acceptable
  1007.               // A supplemental flag and if( ) { } would be really messy
  1008.               goto jump_if_done;
  1009.             }
  1010.             
  1011.           }
  1012.           
  1013.           
  1014.         }
  1015.         // FIN --RECUPERATION LIEN--- 
  1016.         // ------------------------------------------------------------
  1017.         
  1018.         
  1019.         
  1020.       } else {    // lien vide..
  1021.         if (opt.errlog) {
  1022.           fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Warning, link #%d empty"LF,ptr); test_flush;
  1023.         }         
  1024.         error=1;
  1025.         goto jump_if_done;
  1026.       }  // test si url existe (non vide!)
  1027.       
  1028.  
  1029.  
  1030.       // ---tester taille a posteriori---
  1031.       // tester r.adr
  1032.       if (!error) {
  1033.         // erreur, pas de fichier chargΘ:
  1034.         if ((!r.adr) && (r.is_write==0) 
  1035.           && (r.statuscode!=301) 
  1036.           && (r.statuscode!=302) 
  1037.           && (r.statuscode!=303) 
  1038.           && (r.statuscode!=307) 
  1039.           && (r.statuscode!=412)
  1040.           && (r.statuscode!=416)
  1041.          ) { 
  1042.           // error=1;
  1043.           
  1044.           // peut Ωtre que le fichier Θtait trop gros?
  1045.           if ((istoobig(r.totalsize,opt.maxfile_html,opt.maxfile_nonhtml,r.contenttype))
  1046.            || (istoobig(r.totalsize,opt.maxfile_html,opt.maxfile_nonhtml,r.contenttype))) {
  1047.             error=0;
  1048.             if (opt.errlog) {
  1049.               fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Big file cancelled according to user's preferences: %s%s"LF,urladr,urlfil);
  1050.               test_flush;
  1051.             }
  1052.           }
  1053.           // // // error=1;    // ne pas traiter la suite -- euhh si finalement..
  1054.         }
  1055.       }
  1056.       // ---fin tester taille a posteriori---    
  1057.  
  1058.       
  1059.       // -------------------- 
  1060.       // BOGUS MIME TYPE HACK
  1061.       // Check if we have a bogus MIME type
  1062.       // example: 
  1063.       // Content-type="text/html"
  1064.       // and 
  1065.       // Content-disposition="foo.jpg"
  1066.       // --------------------
  1067.       if (!error) {
  1068.         if (r.statuscode == 200) {    // OK (ou 304 en backing)
  1069.           if (r.adr) {    // Written file
  1070.             if ( (is_hypertext_mime(r.contenttype))   /* Is HTML or Js, .. */
  1071.               || (may_be_hypertext_mime(r.contenttype) && (r.adr) )  /* Is real media, .. */
  1072.               ) {
  1073.               if (strnotempty(r.cdispo)) {      // Content-disposition set!
  1074.                 if (ishtml(savename) == 0) {    // Non HTML!!
  1075.                   // patch it!
  1076.                   strcpybuff(r.contenttype,"application/octet-stream");
  1077.                 }
  1078.               }
  1079.             }
  1080.           }
  1081.         }
  1082.         
  1083.         // ------------------------------------
  1084.         // BOGUS MIME TYPE HACK II (the revenge)
  1085.         // Check if we have a bogus MIME type
  1086.         if ( (is_hypertext_mime(r.contenttype))   /* Is HTML or Js, .. */
  1087.           || (may_be_hypertext_mime(r.contenttype))  /* Is real media, .. */
  1088.           ) {
  1089.           if ((r.adr) && (r.size)) {
  1090.             unsigned int map[256];
  1091.             int i;
  1092.             unsigned int nspec = 0;
  1093.             map_characters((unsigned char*)r.adr, (unsigned int)r.size, (unsigned int*)map);
  1094.             for(i = 1 ; i < 32 ; i++) {   //  null chars ignored..
  1095.               if (!is_realspace(i) 
  1096.                 && i != 27        /* Damn you ISO2022-xx! */
  1097.                 ) {
  1098.                 nspec += map[i];
  1099.               }
  1100.             }
  1101.             /* On-the-fly UCS2 to ISO-8859-1 conversion (note: UCS2 should never be used on the net) */
  1102.             if (
  1103.               map[0] > r.size/10
  1104.               &&
  1105.               r.size % 2 == 0
  1106.               &&
  1107.               (
  1108.               ( ((unsigned char) r.adr[0]) == 0xff && ((unsigned char) r.adr[1]) == 0xfe)
  1109.               ||
  1110.               ( ((unsigned char) r.adr[0]) == 0xfe && ((unsigned char) r.adr[1]) == 0xff)
  1111.               )
  1112.               ) {
  1113.               int lost=0;
  1114.               int i;
  1115.               int swap = (r.adr[0] == 0xff);
  1116.               for(i = 0 ; i < r.size / 2 - 1 ; i++) {
  1117.                 unsigned int unic = 0;
  1118.                 if (swap)
  1119.                   unic = (r.adr[i*2 + 2] << 8) + r.adr[i*2 + 2 + 1];
  1120.                 else
  1121.                   unic = r.adr[i*2 + 2] + (r.adr[i*2 + 2 + 1] << 8);
  1122.                 if (unic <= 255)
  1123.                   r.adr[i] = (char) unic;
  1124.                 else {
  1125.                   r.adr[i] = '?';
  1126.                   lost++;
  1127.                 }
  1128.               }
  1129.               r.size = r.size / 2 - 1;
  1130.               r.adr[r.size] = '\0';
  1131.  
  1132.               if (opt.errlog) {
  1133.                 fspc(opt.errlog,"warning"); fprintf(opt.errlog,"File %s%s converted from UCS2 to 8-bit, %d characters lost during conversion (better to use UTF-8)"LF, urladr, urlfil, lost);
  1134.                 test_flush;
  1135.               }
  1136.             } else if ((nspec > r.size / 100) && (nspec > 10)) {    // too many special characters
  1137.               strcpybuff(r.contenttype,"application/octet-stream");
  1138.               if (opt.errlog) {
  1139.                 fspc(opt.errlog,"warning"); fprintf(opt.errlog,"File not parsed, looks like binary: %s%s"LF,urladr,urlfil);
  1140.                 test_flush;
  1141.               }
  1142.             }
  1143.  
  1144.             /* This hack allows to avoid problems with parsing '\0' characters  */
  1145.             for(i = 0 ; i < r.size ; i++) {
  1146.               if (r.adr[i] == '\0') r.adr[i] = ' ';
  1147.             }
  1148.  
  1149.           }
  1150.  
  1151.  
  1152.         }
  1153.       }
  1154.       
  1155.       // -------------------- 
  1156.       // REAL MEDIA HACK
  1157.       // Check if we have to load locally the file
  1158.       // --------------------
  1159.       if (!error) {
  1160.         if (r.statuscode == 200) {    // OK (ou 304 en backing)
  1161.           if (r.adr==NULL) {    // Written file
  1162.             if (may_be_hypertext_mime(r.contenttype)) {   // to parse!
  1163.               LLint sz;
  1164.               sz=fsize(savename);
  1165.               if (sz>0) {   // ok, exists!
  1166.                 if (sz < 1024) {   // ok, small file --> to parse!
  1167.                   FILE* fp=fopen(savename,"rb");
  1168.                   if (fp) {
  1169.                     r.adr=malloct((int)sz + 2);
  1170.                     if (r.adr) {
  1171.                       if (fread(r.adr,1,(INTsys)sz,fp) == sz) {
  1172.                         r.size=sz;
  1173.                       } else {
  1174.                         freet(r.adr);
  1175.                         r.size=0;
  1176.                         r.adr = NULL;
  1177.                         r.statuscode=-1;
  1178.                         strcpybuff(r.msg, ".RAM read error");
  1179.                       }
  1180.                       fclose(fp);
  1181.                       fp=NULL;
  1182.                       // remove (temporary) file!
  1183.                       remove(savename);
  1184.                     }
  1185.                     if (fp)
  1186.                       fclose(fp);
  1187.                   }
  1188.                 }
  1189.               }
  1190.             }
  1191.           }
  1192.         }
  1193.       }
  1194.       // EN OF REAL MEDIA HACK
  1195.       
  1196.  
  1197.       // ---stockage en cache---
  1198.       // stocker dans le cache?
  1199.       /*
  1200.       if (!error) {
  1201.         if (ptr>0) {
  1202.           if (liens[ptr]) {
  1203.             xxcache_mayadd(&opt,&cache,&r,urladr,urlfil,savename);
  1204.           } else
  1205.             error=1;
  1206.         }
  1207.       }
  1208.       */
  1209.       // ---fin stockage en cache---
  1210.       
  1211.       
  1212.       
  1213.       /*
  1214.          **************************************
  1215.          Check "Moved permanently" and other similar errors, retrying URLs if necessary and handling
  1216.          redirect pages.
  1217.       */
  1218.       if (!error) {
  1219.         char buff_err_msg[1024];
  1220.         htsmoduleStruct str;
  1221.         htsmoduleStructExtended stre;
  1222.         buff_err_msg[0] = '\0';
  1223.         memset(&str, 0, sizeof(str));
  1224.         memset(&stre, 0, sizeof(stre));
  1225.         /* */
  1226.         str.err_msg = buff_err_msg;
  1227.         str.filename = savename;
  1228.         str.mime = r.contenttype;
  1229.         str.url_host = urladr;
  1230.         str.url_file = urlfil;
  1231.         str.size = (int) r.size;
  1232.         /* */
  1233.         str.addLink = htsAddLink;
  1234.         /* */
  1235.         str.liens = liens;
  1236.         str.opt = &opt;
  1237.         str.back = back;
  1238.         str.back_max = back_max;
  1239.         str.cache = &cache;
  1240.         str.hashptr = hashptr;
  1241.         str.numero_passe = numero_passe;
  1242.         str.add_tab_alloc = add_tab_alloc;
  1243.         /* */
  1244.         str.lien_tot_ = &lien_tot;
  1245.         str.ptr_ = &ptr;
  1246.         str.lien_size_ = &lien_size;
  1247.         str.lien_buffer_ = &lien_buffer;
  1248.         /* */
  1249.         /* */
  1250.         stre.r_ = &r;
  1251.         /* */
  1252.         stre.error_ = &error;
  1253.         stre.exit_xh_ = &exit_xh;
  1254.         stre.store_errpage_ = &store_errpage;
  1255.         /* */
  1256.         stre.base = base;
  1257.         stre.codebase = codebase;
  1258.         /* */
  1259.         stre.filters_ = &filters;
  1260.         stre.filptr_ = &filptr;
  1261.         stre.robots_ = &robots;
  1262.         stre.hash_ = &hash;
  1263.         stre.lien_max_ = &lien_max;
  1264.         /* */
  1265.         stre.makeindex_done_ = &makeindex_done;
  1266.         stre.makeindex_fp_ = &makeindex_fp;
  1267.         stre.makeindex_links_ = &makeindex_links;
  1268.         stre.makeindex_firstlink_ = makeindex_firstlink;
  1269.         /* */
  1270.         stre.template_header_ = template_header;
  1271.         stre.template_body_ = template_body;
  1272.         stre.template_footer_ = template_footer;
  1273.         /* */
  1274.         stre.stat_fragment_ = &stat_fragment;
  1275.         stre.makestat_time = makestat_time;
  1276.         stre.makestat_fp = makestat_fp;
  1277.         stre.makestat_total_ = &makestat_total;
  1278.         stre.makestat_lnk_ = &makestat_lnk;
  1279.         stre.maketrack_fp = maketrack_fp;
  1280.         
  1281.         /* Parse */
  1282.         if (hts_mirror_check_moved(&str, &stre) != 0) {
  1283.           XH_uninit;
  1284.           return -1;
  1285.         }
  1286.         
  1287.       }
  1288.  
  1289.     }  // if !error
  1290.     
  1291.     if (!error) {
  1292. #if DEBUG_SHOWTYPES
  1293.       if (strstr(REG,r.contenttype)==NULL) {
  1294.         strcatbuff(REG,r.contenttype);
  1295.         strcatbuff(REG,"\n");
  1296.         printf("%s\n",r.contenttype);
  1297.         io_flush;
  1298.       }
  1299. #endif
  1300.       
  1301.  
  1302.       // ------------------------------------------------------
  1303.       // ok, fichier chargΘ localement
  1304.       // ------------------------------------------------------
  1305.       
  1306.       // VΘrificateur d'intΘgritΘ
  1307.       #if DEBUG_CHECKINT
  1308.       {
  1309.         int i;
  1310.         for(i=0;i<back_max;i++) {
  1311.           char si[256];
  1312.           sprintf(si,"Test global aprΦs back_wait, index %d",i);
  1313.           _CHECKINT(&back[i],si)
  1314.         }
  1315.       }
  1316.       #endif
  1317.  
  1318.  
  1319.       /* info: updated */
  1320.       /*
  1321.       if (ptr>0) {
  1322.         // "mis α jour"
  1323.         if ((!r.notmodified) && (opt.is_update) && (!store_errpage)) {    // page modifiΘe
  1324.           if (strnotempty(savename)) {
  1325.             HTS_STAT.stat_updated_files++;
  1326.             if (opt.log!=NULL) {
  1327.               //if ((opt.debug>0) && (opt.log!=NULL)) {
  1328.               fspc(opt.log,"info"); fprintf(opt.log,"File updated: %s%s"LF,urladr,urlfil);
  1329.               test_flush;
  1330.             }
  1331.           }
  1332.         } else {
  1333.           if (!store_errpage) {
  1334.             if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1335.               fspc(opt.log,"info"); fprintf(opt.log,"File recorded: %s%s"LF,urladr,urlfil);
  1336.               test_flush;
  1337.             }
  1338.           }
  1339.         }
  1340.       }
  1341.       */
  1342.       
  1343.       // ------------------------------------------------------
  1344.       // traitement (parsing)
  1345.       // ------------------------------------------------------
  1346.  
  1347.       // traiter
  1348.       if (
  1349.            ( (is_hypertext_mime(r.contenttype))   /* Is HTML or Js, .. */
  1350.              || (may_be_hypertext_mime(r.contenttype) && (r.adr) )  /* Is real media, .. */
  1351.            )
  1352.         && (liens[ptr]->depth>0)            /* Depth > 0 (recurse depth) */
  1353.         && (r.adr!=NULL)        /* HTML Data exists */
  1354.         && (r.size>0)           /* And not empty */
  1355.         && (!store_errpage)     /* Not an html error page */
  1356.         && (savename[0]!='\0')  /* Output filename exists */
  1357.         ) {    // ne traiter que le html si autorisΘ
  1358.         // -- -- -- --
  1359.         // Parsing HTML
  1360.         if (!error) {
  1361.           /* Info for wrappers */
  1362.           if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1363.             fspc(opt.log,"info"); fprintf(opt.log,"engine: check-html: %s%s"LF,urladr,urlfil);
  1364.           }
  1365.           {
  1366.             char buff_err_msg[1024];
  1367.             htsmoduleStruct str;
  1368.             htsmoduleStructExtended stre;
  1369.             buff_err_msg[0] = '\0';
  1370.             memset(&str, 0, sizeof(str));
  1371.             memset(&stre, 0, sizeof(stre));
  1372.             /* */
  1373.             str.err_msg = buff_err_msg;
  1374.             str.filename = savename;
  1375.             str.mime = r.contenttype;
  1376.             str.url_host = urladr;
  1377.             str.url_file = urlfil;
  1378.             str.size = (int) r.size;
  1379.             /* */
  1380.             str.addLink = htsAddLink;
  1381.             /* */
  1382.             str.liens = liens;
  1383.             str.opt = &opt;
  1384.             str.back = back;
  1385.             str.back_max = back_max;
  1386.             str.cache = &cache;
  1387.             str.hashptr = hashptr;
  1388.             str.numero_passe = numero_passe;
  1389.             str.add_tab_alloc = add_tab_alloc;
  1390.             /* */
  1391.             str.lien_tot_ = &lien_tot;
  1392.             str.ptr_ = &ptr;
  1393.             str.lien_size_ = &lien_size;
  1394.             str.lien_buffer_ = &lien_buffer;
  1395.             /* */
  1396.             /* */
  1397.             stre.r_ = &r;
  1398.             /* */
  1399.             stre.error_ = &error;
  1400.             stre.exit_xh_ = &exit_xh;
  1401.             stre.store_errpage_ = &store_errpage;
  1402.             /* */
  1403.             stre.base = base;
  1404.             stre.codebase = codebase;
  1405.             /* */
  1406.             stre.filters_ = &filters;
  1407.             stre.filptr_ = &filptr;
  1408.             stre.robots_ = &robots;
  1409.             stre.hash_ = &hash;
  1410.             stre.lien_max_ = &lien_max;
  1411.             /* */
  1412.             stre.makeindex_done_ = &makeindex_done;
  1413.             stre.makeindex_fp_ = &makeindex_fp;
  1414.             stre.makeindex_links_ = &makeindex_links;
  1415.             stre.makeindex_firstlink_ = makeindex_firstlink;
  1416.             /* */
  1417.             stre.template_header_ = template_header;
  1418.             stre.template_body_ = template_body;
  1419.             stre.template_footer_ = template_footer;
  1420.             /* */
  1421.             stre.stat_fragment_ = &stat_fragment;
  1422.             stre.makestat_time = makestat_time;
  1423.             stre.makestat_fp = makestat_fp;
  1424.             stre.makestat_total_ = &makestat_total;
  1425.             stre.makestat_lnk_ = &makestat_lnk;
  1426.             stre.maketrack_fp = maketrack_fp;
  1427.             
  1428.             /* Parse */
  1429.             if (htsparse(&str, &stre) != 0) {
  1430.               XH_uninit;
  1431.               return -1;
  1432.             }
  1433.  
  1434.  
  1435.           // I'll have to segment this part
  1436. // #include "htsparse.c"
  1437.  
  1438.  
  1439.           }
  1440.         }
  1441.         // Fin parsing HTML
  1442.         // -- -- -- --
  1443.  
  1444.  
  1445.       }  // si text/html
  1446.       // -- -- --
  1447.       else {    // sauver fichier quelconque
  1448.         // -- -- --
  1449.         // sauver fichier
  1450.  
  1451.  
  1452.         /* En cas d'erreur, vΘrifier que fichier d'erreur existe */
  1453.         if (strnotempty(savename) == 0) {           // chemin de sauvegarde existant
  1454.           if (strcmp(urlfil,"/robots.txt")==0) {    // pas robots.txt
  1455.             if (store_errpage) {                    // c'est une page d'erreur
  1456.               int create_html_warning=0;
  1457.               int create_gif_warning=0;
  1458.               switch (ishtml(urlfil)) {      /* pas fichier html */
  1459.               case 0:                        /* non html */
  1460.                 {
  1461.                   char buff[256];
  1462.                   guess_httptype(buff,urlfil);
  1463.                   if (strcmp(buff,"image/gif")==0)
  1464.                     create_gif_warning=1;
  1465.                 }
  1466.                 break;
  1467.               case 1:                        /* html */
  1468.                 if (!r.adr) {
  1469.                 }
  1470.                 break;
  1471.               default:                       /* don't know.. */
  1472.                 break;    
  1473.               }
  1474.               /* CrΘer message d'erreur ? */
  1475.               if (create_html_warning) {
  1476.                 char* adr=(char*)malloct(strlen(HTS_DATA_ERROR_HTML)+1100);
  1477.                 if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1478.                   fspc(opt.log,"info"); fprintf(opt.log,"Creating HTML warning file (%s)"LF,r.msg);
  1479.                   test_flush;
  1480.                 }
  1481.                 if (adr) {
  1482.                   if (r.adr) {
  1483.                     freet(r.adr);
  1484.                     r.adr=NULL;
  1485.                   }
  1486.                   sprintf(adr,HTS_DATA_ERROR_HTML,r.msg);
  1487.                   r.adr=adr;
  1488.                 }
  1489.               } else if (create_gif_warning) {
  1490.                 char* adr=(char*)malloct(HTS_DATA_UNKNOWN_GIF_LEN);
  1491.                 if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1492.                   fspc(opt.log,"info"); fprintf(opt.log,"Creating GIF dummy file (%s)"LF,r.msg);
  1493.                   test_flush;
  1494.                 }
  1495.                 if (r.adr) {
  1496.                   freet(r.adr);
  1497.                   r.adr=NULL;
  1498.                 }
  1499.                 memcpy(adr, HTS_DATA_UNKNOWN_GIF, HTS_DATA_UNKNOWN_GIF_LEN);
  1500.                 r.adr=adr;
  1501.               }
  1502.             }
  1503.           }
  1504.         }
  1505.  
  1506.         if (strnotempty(savename) == 0) {    // pas de chemin de sauvegarde
  1507.           if (strcmp(urlfil,"/robots.txt")==0) {    // robots.txt
  1508.             if (r.adr) {
  1509.               int bptr=0;
  1510.               char line[1024];
  1511.               char buff[8192];
  1512.               char infobuff[8192];
  1513.               int record=0;
  1514.               line[0]='\0'; buff[0]='\0'; infobuff[0]='\0';
  1515.               //
  1516. #if DEBUG_ROBOTS
  1517.               printf("robots.txt dump:\n%s\n",r.adr);
  1518. #endif
  1519.               do {
  1520.                 char* comm;
  1521.                 int llen;
  1522.                 bptr+=binput(r.adr+bptr, line, sizeof(line) - 2);
  1523.                 /* strip comment */
  1524.                 comm=strchr(line, '#');
  1525.                 if (comm != NULL) {
  1526.                   *comm = '\0';
  1527.                 }
  1528.                 /* strip spaces */
  1529.                 llen=strlen(line);
  1530.                 while(llen > 0 && is_realspace(line[llen - 1])) {
  1531.                   line[llen - 1] = '\0';
  1532.                   llen--;
  1533.                 }
  1534.                 if (strfield(line,"user-agent:")) {
  1535.                   char* a;
  1536.                   a=line+11;
  1537.                   while(is_realspace(*a)) a++;    // sauter espace(s)
  1538.                   if ( *a == '*') {
  1539.                     if (record != 2)
  1540.                       record=1;    // c pour nous
  1541.                   } else if (strfield(a,"httrack") || strfield(a,"winhttrack") || strfield(a,"webhttrack")) {
  1542.                     buff[0]='\0';      // re-enregistrer
  1543.                     infobuff[0]='\0';
  1544.                     record=2;          // locked
  1545. #if DEBUG_ROBOTS
  1546.                     printf("explicit disallow for httrack\n");
  1547. #endif
  1548.                   }
  1549.                   else record=0;
  1550.                 } else if (record) {
  1551.                   if (strfield(line,"disallow:")) {
  1552.                     char* a=line+9;
  1553.                     while(is_realspace(*a))
  1554.                       a++;    // sauter espace(s)
  1555.                     if (strnotempty(a)) {
  1556.                       if (strcmp(a,"/") != 0) {      /* ignoring disallow: / */
  1557.                         if ( (strlen(buff) + strlen(a) + 8) < sizeof(buff)) {
  1558.                           strcatbuff(buff,a);
  1559.                           strcatbuff(buff,"\n");
  1560.                           if ( (strlen(infobuff) + strlen(a) + 8) < sizeof(infobuff)) {
  1561.                             if (strnotempty(infobuff)) strcatbuff(infobuff,", ");
  1562.                             strcatbuff(infobuff,a);
  1563.                           }
  1564.                         }
  1565.                       } else {
  1566.                         if (opt.errlog!=NULL) {
  1567.                           fspc(opt.errlog,"info"); fprintf(opt.errlog,"Note: %s robots.txt rules are too restrictive, ignoring /"LF,urladr);
  1568.                           test_flush;
  1569.                         }
  1570.                       }
  1571.                     }
  1572.                   }
  1573.                 }
  1574.               } while( (bptr<r.size) && (strlen(buff) < (sizeof(buff) - 32) ) );
  1575.               if (strnotempty(buff)) {
  1576.                 checkrobots_set(&robots,urladr,buff);
  1577.                 if (opt.log!=NULL) {
  1578.                   if (opt.log != opt.errlog) {
  1579.                     fspc(opt.log,"info"); fprintf(opt.log,"Note: robots.txt forbidden links for %s are: %s"LF,urladr,infobuff);
  1580.                     test_flush;
  1581.                   } 
  1582.                 }
  1583.                 if (opt.errlog!=NULL) {
  1584.                   fspc(opt.errlog,"info"); fprintf(opt.errlog,"Note: due to %s remote robots.txt rules, links begining with these path will be forbidden: %s (see in the options to disable this)"LF,urladr,infobuff);
  1585.                   test_flush;
  1586.                 }
  1587.               }
  1588.             }
  1589.           }
  1590.         } else if (r.is_write) {    // dΘja sauvΘ sur disque
  1591.           /*
  1592.           if (!ishttperror(r.statuscode))
  1593.             HTS_STAT.stat_files++;
  1594.           HTS_STAT.stat_bytes+=r.size;
  1595.           */
  1596.           //printf("ok......\n");
  1597.         } else {
  1598.           // Si on doit sauver une page HTML sans la scanner, cela signifie que le niveau de
  1599.           // rΘcursion nous en empΩche
  1600.           // Dans ce cas on met un fichier indiquant ce fait
  1601.           // Si par la suite on doit retraiter ce fichier avec un niveau de rΘcursion plus
  1602.           // fort, on supprimera le readme, et on scannera le fichier html!
  1603.           // note: sautΘ si store_errpage (cαd si page d'erreur, non α scanner!)
  1604.           if ( (is_hypertext_mime(r.contenttype)) && (!store_errpage) && (r.size>0)) {  // c'est du html!!
  1605.             char tempo[HTS_URLMAXSIZE*2];
  1606.             FILE* fp;
  1607.             tempo[0]='\0';
  1608.             strcpybuff(tempo,savename);
  1609.             strcatbuff(tempo,".readme");
  1610.             
  1611. #if HTS_DOSNAME
  1612.             // remplacer / par des slash arriΦre
  1613.             {
  1614.               int i=0;
  1615.               while(tempo[i]) {
  1616.                 if (tempo[i]=='/')
  1617.                   tempo[i]='\\';
  1618.                 i++;
  1619.               } 
  1620.             } 
  1621.             // a partir d'ici le slash devient antislash
  1622. #endif
  1623.             
  1624.             if ((fp=fopen(tempo,"wb"))!=NULL) {
  1625.               fprintf(fp,"Info-file generated by HTTrack Website Copier "HTTRACK_VERSION"%s"CRLF""CRLF, WHAT_is_available);
  1626.               fprintf(fp,"The file %s has not been scanned by HTS"CRLF,savename);
  1627.               fprintf(fp,"Some links contained in it may be unreachable locally."CRLF);
  1628.               fprintf(fp,"If you want to get these files, you have to set an upper recurse level, ");
  1629.               fprintf(fp,"and to rescan the URL."CRLF);
  1630.               fclose(fp);
  1631. #if HTS_WIN==0
  1632.               chmod(tempo,HTS_ACCESS_FILE);      
  1633. #endif
  1634.               usercommand(&opt,0,NULL,fconv(tempo),"","");
  1635.             }
  1636.             
  1637.             
  1638.             if ( (opt.debug>0) && (opt.errlog!=NULL) ) {
  1639.               fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Warning: store %s without scan: %s"LF,r.contenttype,savename);
  1640.               test_flush;
  1641.             }
  1642.           } else {
  1643.             if ((opt.getmode & 2)!=0) {    // ok autorisΘ
  1644.               if ( (opt.debug>1) && (opt.log!=NULL) ) {
  1645.                 fspc(opt.log,"debug"); fprintf(opt.log,"Store %s: %s"LF,r.contenttype,savename);
  1646.                 test_flush;
  1647.               }
  1648.             } else {    // lien non autorisΘ! (ex: cgi-bin en html)
  1649.               if ((opt.debug>1) && (opt.log!=NULL)) {
  1650.                 fspc(opt.log,"debug"); fprintf(opt.log,"non-html file ignored after upload at %s : %s"LF,urladr,urlfil);
  1651.                 test_flush;
  1652.               } 
  1653.               if (r.adr) {
  1654.                 freet(r.adr); r.adr=NULL;
  1655.               }
  1656.             }
  1657.           }
  1658.           
  1659.           //printf("extern=%s\n",r.contenttype);
  1660.  
  1661.           // ATTENTION C'EST ICI QU'ON SAUVE LE FICHIER!!          
  1662.           if (r.adr) {
  1663.             if (filesave(&opt,r.adr,(int)r.size,savename,urladr,urlfil)!=0) {
  1664.               int fcheck;
  1665.               if ((fcheck=check_fatal_io_errno())) {
  1666.                 exit_xh=-1;   /* fatal error */
  1667.               }
  1668.               if (opt.errlog) {   
  1669.                 fspc(opt.errlog,"error"); fprintf(opt.errlog,"Unable to save file %s : %s"LF, savename, strerror(errno));
  1670.                 if (fcheck) {
  1671.                   fspc(opt.errlog,"error");
  1672.                   fprintf(opt.errlog,"* * Fatal write error, giving up"LF);
  1673.                 }
  1674.                 test_flush;
  1675.               }
  1676.             } else {
  1677.               /*
  1678.               if (!ishttperror(r.statuscode))
  1679.                 HTS_STAT.stat_files++;
  1680.               HTS_STAT.stat_bytes+=r.size;
  1681.               */
  1682.             }
  1683.           }
  1684.           
  1685.         }
  1686.   
  1687.  
  1688.         /* Parsing of other media types (java, ram..) */
  1689.         /*
  1690.         if (strfield2(r.contenttype,"audio/x-pn-realaudio")) {
  1691.           if ((opt.debug>1) && (opt.log!=NULL)) {
  1692.             fspc(opt.log,"debug"); fprintf(opt.log,"(Real Media): parsing %s"LF,savename); test_flush;
  1693.           }
  1694.           if (fexist(savename)) {   // ok, existe bien!
  1695.             FILE* fp=fopen(savename,"r+b");
  1696.             if (fp) {
  1697.               if (!fseek(fp,0,SEEK_SET)) {
  1698.                 char line[HTS_URLMAXSIZE*2];
  1699.                 linput(fp,line,HTS_URLMAXSIZE);
  1700.                 if (strnotempty(line)) {
  1701.                   if ((opt.debug>1) && (opt.log!=NULL)) {
  1702.                     fspc(opt.log,"debug"); fprintf(opt.log,"(Real Media): detected %s"LF,line); test_flush;
  1703.                   }
  1704.                 }
  1705.               }
  1706.               fclose(fp);
  1707.             }
  1708.           }
  1709.         } else */
  1710.  
  1711.  
  1712.         /* External modules */
  1713.         if (opt.parsejava && fexist(savename)) {
  1714.           char buff_err_msg[1024];
  1715.           htsmoduleStruct str;
  1716.           buff_err_msg[0] = '\0';
  1717.           memset(&str, 0, sizeof(str));
  1718.           /* */
  1719.           str.err_msg = buff_err_msg;
  1720.           str.filename = savename;
  1721.           str.mime = r.contenttype;
  1722.           str.url_host = urladr;
  1723.           str.url_file = urlfil;
  1724.           str.size = (int) r.size;
  1725.           /* */
  1726.           str.addLink = htsAddLink;
  1727.           /* */
  1728.           str.liens = liens;
  1729.           str.opt = &opt;
  1730.           str.back = back;
  1731.           str.back_max = back_max;
  1732.           str.cache = &cache;
  1733.           str.hashptr = hashptr;
  1734.           str.numero_passe = numero_passe;
  1735.           str.add_tab_alloc = add_tab_alloc;
  1736.           /* */
  1737.           str.lien_tot_ = &lien_tot;
  1738.           str.ptr_ = &ptr;
  1739.           str.lien_size_ = &lien_size;
  1740.           str.lien_buffer_ = &lien_buffer;
  1741.           /* Parse if recognized */
  1742.           switch(hts_parse_externals(&str)) {
  1743.           case 1:
  1744.             if ((opt.debug>1) && (opt.log!=NULL)) {
  1745.               fspc(opt.log,"debug"); fprintf(opt.log,"(External module): parsed successfully %s"LF,savename); test_flush;
  1746.             }
  1747.             break;
  1748.           case 0:
  1749.             if ((opt.debug>1) && (opt.log!=NULL)) {
  1750.               fspc(opt.log,"debug"); fprintf(opt.log,"(External module): couldn't parse successfully %s : %s"LF,savename, str.err_msg); test_flush;
  1751.             }
  1752.             break;
  1753.           }
  1754.         }
  1755.              
  1756.         
  1757.       }  // text/html ou autre
  1758.       
  1759.  
  1760.       /* Post-processing */
  1761.       if (fexist(savename)) {
  1762.         usercommand(&opt, 0, NULL, savename, urladr, urlfil);
  1763.       }
  1764.  
  1765.  
  1766.     }  // if !error
  1767.     
  1768.  
  1769. jump_if_done:
  1770.     // libΘrer les liens
  1771.     if (r.adr) { 
  1772.       freet(r.adr); 
  1773.       r.adr=NULL; 
  1774.     }   // libΘrer la mΘmoire!
  1775.     
  1776.     // prochain lien
  1777.     ptr++;
  1778.     
  1779.     // faut-il sauter le(s) lien(s) suivant(s)? (fichiers images α passer aprΦs les html)
  1780.     if (opt.getmode & 4) {    // sauver les non html aprΦs
  1781.       // sauter les fichiers selon la passe
  1782.       if (!numero_passe) {
  1783.         while((ptr<lien_tot)?(   liens[ptr]->pass2):0) ptr++;
  1784.       } else {
  1785.         while((ptr<lien_tot)?( ! liens[ptr]->pass2):0) ptr++;
  1786.       }
  1787.       if (ptr>=lien_tot) {     // fin de boucle
  1788.         if (!numero_passe) { // premiΦre boucle
  1789.           if ((opt.debug>1) && (opt.log!=NULL)) {
  1790.             fprintf(opt.log,LF"Now getting non-html files..."LF);
  1791.             test_flush;
  1792.           }
  1793.           numero_passe=1;   // seconde boucle
  1794.           ptr=0;
  1795.           // prochain pass2
  1796.           while((ptr<lien_tot)?(!liens[ptr]->pass2):0) ptr++;
  1797.           
  1798.           //printf("first link==%d\n");
  1799.           
  1800.         }
  1801.       }  
  1802.     }
  1803.  
  1804.     // copy abort state if necessary from outside
  1805.     if (!exit_xh && opt.state.exit_xh) {
  1806.       exit_xh=opt.state.exit_xh;
  1807.     }
  1808.     // a-t-on dΘpassΘ le quota?
  1809.     if (!back_checkmirror(&opt)) {
  1810.       ptr=lien_tot;
  1811.     } else if (exit_xh) {  // sortir
  1812.       if (opt.errlog) {
  1813.         fspc(opt.errlog,"info"); 
  1814.         if (exit_xh==1) {
  1815.           fprintf(opt.errlog,"Exit requested by shell or user"LF);
  1816.         } else {
  1817.           fprintf(opt.errlog,"Exit requested by engine"LF);
  1818.         }
  1819.         test_flush;
  1820.       } 
  1821.       ptr=lien_tot;
  1822.     }
  1823.   } while(ptr<lien_tot);
  1824.   //
  1825.   //
  1826.   //
  1827.   
  1828.   /*
  1829.   Ensure the index is being closed
  1830.   */
  1831.   HT_INDEX_END;
  1832.   
  1833.   /* 
  1834.     updating-a-remotely-deteted-website hack
  1835.     no much data transfered, no data saved
  1836.     <no files successfulyl saved>
  1837.     we assume that something was bad (no connection)
  1838.     just backup old cache and restore everything
  1839.   */
  1840.   if (
  1841.     (HTS_STAT.stat_files <= 0) 
  1842.     && 
  1843.     (HTS_STAT.HTS_TOTAL_RECV < 32768)    /* should be fine */
  1844.     ) {
  1845.     if (opt.errlog) {
  1846.       fspc(opt.errlog,"info"); fprintf(opt.errlog,"No data seems to have been transfered during this session! : restoring previous one!"LF);
  1847.       test_flush;
  1848.     } 
  1849.     XH_uninit;
  1850.     if ( (fexist(fconcat(opt.path_log,"hts-cache/old.dat"))) && (fexist(fconcat(opt.path_log,"hts-cache/old.ndx"))) ) {
  1851.       remove(fconcat(opt.path_log,"hts-cache/new.dat"));
  1852.       remove(fconcat(opt.path_log,"hts-cache/new.ndx"));
  1853.       remove(fconcat(opt.path_log,"hts-cache/new.lst"));
  1854.       remove(fconcat(opt.path_log,"hts-cache/new.txt"));
  1855.       rename(fconcat(opt.path_log,"hts-cache/old.dat"),fconcat(opt.path_log,"hts-cache/new.dat"));
  1856.       rename(fconcat(opt.path_log,"hts-cache/old.ndx"),fconcat(opt.path_log,"hts-cache/new.ndx"));
  1857.       rename(fconcat(opt.path_log,"hts-cache/old.lst"),fconcat(opt.path_log,"hts-cache/new.lst"));
  1858.       rename(fconcat(opt.path_log,"hts-cache/old.txt"),fconcat(opt.path_log,"hts-cache/new.txt"));
  1859.     }
  1860.     exit_xh=2;        /* interrupted (no connection detected) */
  1861.     return 1;
  1862.   }
  1863.  
  1864.   // info text  
  1865.   if (cache.txt) {
  1866.     fclose(cache.txt); cache.txt=NULL;
  1867.   }
  1868.  
  1869.   // purger!
  1870.   if (cache.lst) {
  1871.     fclose(cache.lst); cache.lst=NULL;
  1872.     if (opt.delete_old) {
  1873.       FILE *old_lst,*new_lst;
  1874.       //
  1875. #if HTS_ANALYSTE
  1876.       _hts_in_html_parsing=3;
  1877. #endif
  1878.       //
  1879.       old_lst=fopen(fconcat(opt.path_log,"hts-cache/old.lst"),"rb");
  1880.       if (old_lst) {
  1881.         LLint sz=fsize(fconcat(opt.path_log,"hts-cache/new.lst"));
  1882.         new_lst=fopen(fconcat(opt.path_log,"hts-cache/new.lst"),"rb");
  1883.         if ((new_lst) && (sz>0)) {
  1884.           char* adr=(char*) malloct((INTsys)sz);
  1885.           if (adr) {
  1886.             if (fread(adr,1,(INTsys)sz,new_lst) == sz) {
  1887.               char line[1100];
  1888.               int purge=0;
  1889.               while(!feof(old_lst)) {
  1890.                 linput(old_lst,line,1000);
  1891.                 if (!strstr(adr,line)) {    // fichier non trouvΘ dans le nouveau?
  1892.                   char file[HTS_URLMAXSIZE*2];
  1893.                   strcpybuff(file,opt.path_html);
  1894.                   strcatbuff(file,line+1);
  1895.                   file[strlen(file)-1]='\0';
  1896.                   if (fexist(file)) {       // toujours sur disque: virer
  1897.                     if (opt.log) {
  1898.                       fspc(opt.log,"info"); fprintf(opt.log,"Purging %s"LF,file);
  1899.                     }
  1900.                     remove(file); purge=1;
  1901.                   }
  1902.                 }
  1903.               }
  1904.               {
  1905.                 fseek(old_lst,0,SEEK_SET);
  1906.                 while(!feof(old_lst)) {
  1907.                   linput(old_lst,line,1000);
  1908.                   while(strnotempty(line) && (line[strlen(line)-1]!='/') && (line[strlen(line)-1]!='\\')) {
  1909.                     line[strlen(line)-1]='\0';
  1910.                   }
  1911.                   if (strnotempty(line))
  1912.                     line[strlen(line)-1]='\0';
  1913.                   if (strnotempty(line))
  1914.                     if (!strstr(adr,line)) {    // non trouvΘ?
  1915.                       char file[HTS_URLMAXSIZE*2];
  1916.                       strcpybuff(file,opt.path_html);
  1917.                       strcatbuff(file,line+1);
  1918.                       while ((strnotempty(file)) && (rmdir(file)==0)) {    // ok, ΘliminΘ (existait)
  1919.                         purge=1;
  1920.                         if (opt.log) {
  1921.                           fspc(opt.log,"info"); fprintf(opt.log,"Purging directory %s/"LF,file);
  1922.                           while(strnotempty(file) && (file[strlen(file)-1]!='/') && (file[strlen(file)-1]!='\\')) {
  1923.                             file[strlen(file)-1]='\0';
  1924.                           }
  1925.                           if (strnotempty(file))
  1926.                             file[strlen(file)-1]='\0';
  1927.                         }
  1928.                       }
  1929.                     }
  1930.                 }
  1931.               }
  1932.               //
  1933.               if (!purge) {
  1934.                 if (opt.log) {
  1935.                   fprintf(opt.log,"No files purged"LF);
  1936.                 }
  1937.               }
  1938.             }
  1939.             freet(adr);
  1940.           }
  1941.           fclose(new_lst);
  1942.         }
  1943.         fclose(old_lst);
  1944.       }
  1945.       //
  1946. #if HTS_ANALYSTE
  1947.       _hts_in_html_parsing=0;
  1948. #endif
  1949.     }
  1950.   }
  1951.   // fin purge!
  1952.  
  1953.   // Indexation
  1954.   if (opt.kindex)
  1955.     index_finish(opt.path_html,opt.kindex);
  1956.  
  1957.   // afficher rΘsumΘ dans log
  1958.   if (opt.log!=NULL) {
  1959.     int error   = fspc(NULL,"error");
  1960.     int warning = fspc(NULL,"warning");
  1961.     int info    = fspc(NULL,"info");
  1962.     char htstime[256];
  1963.     char infoupdated[256];
  1964.     // int n=(int) (stat_loaded/(time_local()-HTS_STAT.stat_timestart));
  1965.     LLint n=(LLint) (HTS_STAT.HTS_TOTAL_RECV/(max(1,time_local()-HTS_STAT.stat_timestart)));
  1966.     
  1967.     sec2str(htstime,time_local()-HTS_STAT.stat_timestart);
  1968.     //fprintf(opt.log,LF"HTS-mirror complete in %s : %d links scanned, %d files written (%d bytes overall) [%d bytes received at %d bytes/sec]"LF,htstime,lien_tot-1,HTS_STAT.stat_files,stat_bytes,stat_loaded,n);
  1969.     infoupdated[0] = '\0';
  1970.     if (opt.is_update) {
  1971.       if (HTS_STAT.stat_updated_files < 0) {
  1972.         sprintf(infoupdated, ", %d files updated", (int)HTS_STAT.stat_updated_files);
  1973.       } else {
  1974.         sprintf(infoupdated, ", no files updated");
  1975.       }
  1976.     }
  1977.     fprintf(opt.log,LF
  1978.       "HTTrack mirror complete in %s : "
  1979.       "%d links scanned, %d files written ("LLintP" bytes overall)%s "
  1980.       "["LLintP" bytes received at "LLintP" bytes/sec]",
  1981.       htstime,
  1982.       (int)lien_tot-1,
  1983.       (int)HTS_STAT.stat_files,
  1984.       (LLint)HTS_STAT.stat_bytes,
  1985.       infoupdated,
  1986.       (LLint)HTS_STAT.HTS_TOTAL_RECV,
  1987.       (LLint)n
  1988.     );
  1989.     if (HTS_STAT.total_packed > 0 && HTS_STAT.total_unpacked > 0) {
  1990.       int packed_ratio=(int)((LLint)(HTS_STAT.total_packed*100)/HTS_STAT.total_unpacked);
  1991.       fprintf(opt.log,", "LLintP" bytes transfered using HTTP compression in %d files, ratio %d%%",(LLint)HTS_STAT.total_unpacked,HTS_STAT.total_packedfiles,(int)packed_ratio);
  1992.     }
  1993.     if (!opt.nokeepalive && HTS_STAT.stat_sockid > 0 && HTS_STAT.stat_nrequests > HTS_STAT.stat_sockid) {
  1994.       int rq = (HTS_STAT.stat_nrequests * 10) / HTS_STAT.stat_sockid;
  1995.       fprintf(opt.log,", %d.%d requests per connection", rq/10, rq%10);
  1996.     }
  1997.     fprintf(opt.log,LF);
  1998.     if (error)
  1999.       fprintf(opt.log,"(%d errors, %d warnings, %d messages)"LF,error,warning,info);
  2000.     else
  2001.       fprintf(opt.log,"(No errors, %d warnings, %d messages)"LF,warning,info);
  2002.     test_flush;
  2003.   }
  2004. #if DEBUG_HASH
  2005.   // noter les collisions
  2006.   {
  2007.     int i;
  2008.     int empty1=0,empty2=0,empty3=0;
  2009.     for(i=0;i<HTS_HASH_SIZE;i++) {
  2010.       if (hash.hash[0][i] == -1)
  2011.         empty1++;
  2012.       if (hash.hash[1][i] == -1)
  2013.         empty2++;
  2014.       if (hash.hash[2][i] == -1)
  2015.         empty3++;
  2016.     }
  2017.     printf("\n");
  2018.     printf("Debug info: Hash-table report\n");
  2019.     printf("Number of files entered:   %d\n",hashnumber);
  2020.     printf("Table size:                %d\n",HTS_HASH_SIZE);
  2021.     printf("\n");
  2022.     printf("Longest chain sav:              %d, empty: %d\n",longest_hash[0],empty1);
  2023.     printf("Longest chain adr,fil:          %d, empty: %d\n",longest_hash[1],empty2);
  2024.     printf("Longest chain former_adr/fil:   %d, empty: %d\n",longest_hash[2],empty3);
  2025.     printf("\n");
  2026.   }
  2027. #endif    
  2028.   // fin afficher rΘsumΘ dans log
  2029.  
  2030.   // ending
  2031.   usercommand(&opt,0,NULL,NULL,NULL,NULL);
  2032.  
  2033.   // dΘsallocation mΘmoire & buffers
  2034.   XH_uninit;
  2035.  
  2036.   return 1;    // OK
  2037. }
  2038. // version 2 pour le reste
  2039. // flusher si on doit lire peu α peu le fichier
  2040. #undef test_flush
  2041. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  2042.  
  2043.  
  2044. // Estimate transfer rate
  2045. // a little bit complex, but not too much
  2046. /*
  2047.   .. : idle
  2048.   ^  : event
  2049.  
  2050.   ----|----|----|----|----|----|----|----|---->
  2051.    1    2    3    4    5    6    7    8    9   time (seconds)
  2052.   ----|----|----|----|----|----|----|----|---->
  2053.   ^........^.........^.........^.........^.... timer 0
  2054.   ----^.........^.........^.........^......... timer 1
  2055.            0    1    0    1    0    1    0     timer N sets its statistics
  2056.       *         *         *         *          timer 0 resync timer 1
  2057.  
  2058.   Therefore, each seconds, we resync the transfer rate with 2-seconds
  2059.  
  2060. */
  2061. int engine_stats(void) {
  2062. #if 0
  2063.   static FILE* debug_fp=NULL; /* ok */
  2064.   if (!debug_fp)
  2065.     debug_fp=fopen("esstat.txt","wb");
  2066. #endif
  2067.   HTS_STAT.stat_nsocket=HTS_STAT.stat_errors=HTS_STAT.nbk==0;
  2068.   HTS_STAT.nb=0;
  2069.   if (HTS_STAT.HTS_TOTAL_RECV>2048) {
  2070.     TStamp cdif=mtime_local();
  2071.     int i;
  2072.  
  2073.     for(i=0;i<2;i++) {
  2074.       if ( (cdif - HTS_STAT.istat_timestart[i]) >= 2000) {
  2075.         TStamp dif;
  2076. #if 0
  2077. fprintf(debug_fp,"set timer %d\n",i); fflush(debug_fp);
  2078. #endif
  2079.         dif=cdif - HTS_STAT.istat_timestart[i];
  2080.         if ((TStamp)(dif/1000)>0) {
  2081.           LLint byt=(HTS_STAT.HTS_TOTAL_RECV - HTS_STAT.istat_bytes[i]);
  2082.           HTS_STAT.rate=(LLint)((TStamp) ((TStamp)byt/(dif/1000)));
  2083.           HTS_STAT.istat_idlasttimer=i;      // this timer recently sets the stats
  2084.           //
  2085.           HTS_STAT.istat_bytes[i]=HTS_STAT.HTS_TOTAL_RECV;
  2086.           HTS_STAT.istat_timestart[i]=cdif;
  2087.         }
  2088.         return 1;       /* refreshed */
  2089.       }
  2090.     }
  2091.  
  2092.     // resynchronization between timer 0 (master) and 1 (slave)
  2093.     // timer #0 resync timer #1 when reaching 1 second limit
  2094.     if (HTS_STAT.istat_reference01 != HTS_STAT.istat_timestart[0]) {
  2095.       if ( (cdif - HTS_STAT.istat_timestart[0]) >= 1000) {
  2096. #if 0
  2097. fprintf(debug_fp,"resync timer 1\n"); fflush(debug_fp);
  2098. #endif
  2099.         HTS_STAT.istat_bytes[1]=HTS_STAT.HTS_TOTAL_RECV;
  2100.         HTS_STAT.istat_timestart[1]=cdif;
  2101.         HTS_STAT.istat_reference01=HTS_STAT.istat_timestart[0];
  2102.       }
  2103.     }
  2104.  
  2105.   }
  2106.   return 0;
  2107. }
  2108.  
  2109.  
  2110. #define _FILTERS     (*opt->filters.filters)
  2111. #define _FILTERS_PTR (opt->filters.filptr)
  2112. #define _ROBOTS      ((robots_wizard*)opt->robotsptr)
  2113.  
  2114. // bannir host (trop lent etc)
  2115. void host_ban(httrackp* opt,lien_url** liens,int ptr,int lien_tot,lien_back* back,int back_max,char* host) {
  2116.   //int l;
  2117.   int i;
  2118.  
  2119.   if (host[0]=='!')
  2120.     return;    // erreur.. dΘja cancellΘ.. bizarre.. devrait pas arriver
  2121.  
  2122.   /* sanity check */
  2123.   if (*_FILTERS_PTR + 1 >= opt->maxfilter) {
  2124.     opt->maxfilter += HTS_FILTERSINC;
  2125.     if (filters_init(&_FILTERS, opt->maxfilter, HTS_FILTERSINC) == 0) {
  2126.       printf("PANIC! : Too many filters : >%d [%d]\n",*_FILTERS_PTR,__LINE__);
  2127.       if (opt->errlog) {
  2128.         fprintf(opt->errlog,LF"Too many filters, giving up..(>%d)"LF,*_FILTERS_PTR);
  2129.         fprintf(opt->errlog,"To avoid that: use #F option for more filters (example: -#F5000)"LF);
  2130.         fflush(opt->errlog);
  2131.       }
  2132.       assertf("too many filters - giving up" == NULL);
  2133.     }
  2134.   }
  2135.  
  2136.   // interdire host
  2137.   assertf((*_FILTERS_PTR) < opt->maxfilter);
  2138.   if (*_FILTERS_PTR < opt->maxfilter) {
  2139.     strcpybuff(_FILTERS[*_FILTERS_PTR],"-");
  2140.     strcatbuff(_FILTERS[*_FILTERS_PTR],host);
  2141.     strcatbuff(_FILTERS[*_FILTERS_PTR],"/*");     // host/ * interdit
  2142.     (*_FILTERS_PTR)++; 
  2143.   }
  2144.   
  2145.   // oups
  2146.   if (strlen(host)<=1) {    // euhh?? longueur <= 1
  2147.     if (strcmp(host,"file://")) {
  2148.       //## if (host[0]!=lOCAL_CHAR) {  // pas local
  2149.       if (opt->log!=NULL) {
  2150.         fprintf(opt->log,"PANIC! HostCancel detected memory leaks [char %d]"LF,host[0]); test_flush;
  2151.       }          
  2152.       return;  // purΘe
  2153.     }
  2154.   }
  2155.   
  2156.   // couper connexion
  2157.   for(i=0;i<back_max;i++) {
  2158.     if (back[i].status>=0)    // rΘception OU prΩt
  2159.       if (strfield2(back[i].url_adr,host)) {
  2160. #if HTS_DEBUG_CLOSESOCK
  2161.         DEBUG_W("host control: deletehttp\n");
  2162. #endif
  2163.         back[i].status=0;  // terminΘ
  2164.         if (back[i].r.soc!=INVALID_SOCKET) deletehttp(&back[i].r);
  2165.         back[i].r.soc=INVALID_SOCKET;
  2166.         back[i].r.statuscode=-2;    // timeout (peu importe si c'est un traffic jam)
  2167.         strcpybuff(back[i].r.msg,"Link Cancelled by host control");
  2168.         
  2169.         if ((opt->debug>1) && (opt->log!=NULL)) {
  2170.           fprintf(opt->log,"Shutdown: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2171.         }          
  2172.       }
  2173.   }
  2174.   
  2175.   // effacer liens
  2176.   //l=strlen(host);
  2177.   for(i=0;i<lien_tot;i++) {
  2178.     //if (liens[i]->adr_len==l) {    // mΩme taille de chaεne
  2179.     // Calcul de taille sΘcurisΘe
  2180.     if (liens[i]) {
  2181.       if (liens[i]->adr) {
  2182.         int l = 0;
  2183.         while((liens[i]->adr[l]) && (l<1020)) l++;
  2184.         if ((l > 0) && (l<1020)) {   // sΘcuritΘ
  2185.           if (strfield2(jump_identification(liens[i]->adr),host)) {    // host
  2186.             if ((opt->debug>1) && (opt->log!=NULL)) {
  2187.               fprintf(opt->log,"Cancel: %s%s"LF,liens[i]->adr,liens[i]->fil); test_flush;
  2188.             }
  2189.             strcpybuff(liens[i]->adr,"!");    // cancel (invalide hash)
  2190. #if HTS_HASH
  2191. #else
  2192.             liens[i]->sav_len=-1;         // taille invalide
  2193. #endif
  2194.             // on efface pas le hash, because si on rencontre le lien, reverif sav..
  2195.           }
  2196.         } else {
  2197.           if (opt->log!=NULL) {
  2198.             char dmp[1040];
  2199.             dmp[0]='\0';
  2200.             strncatbuff(dmp,liens[i]->adr,1024);
  2201.             fprintf(opt->log,"WARNING! HostCancel detected memory leaks [len %d at %d]"LF,l,i); test_flush;
  2202.             fprintf(opt->log,"dump 1024 bytes (address %p): "LF"%s"LF,liens[i]->adr,dmp); test_flush;
  2203.           }          
  2204.         }
  2205.       } else {
  2206.         if (opt->log!=NULL) {
  2207.           fprintf(opt->log,"WARNING! HostCancel detected memory leaks [adr at %d]"LF,i); test_flush;
  2208.         }  
  2209.       }
  2210.     } else {
  2211.       if (opt->log!=NULL) {
  2212.         fprintf(opt->log,"WARNING! HostCancel detected memory leaks [null at %d]"LF,i); test_flush;
  2213.       }  
  2214.     }
  2215.     //}
  2216.   }
  2217. }
  2218.  
  2219.  
  2220. #if 0
  2221. /* Init structure */
  2222. /* 1 : init */
  2223. /* -1 : off */
  2224. /* 0 : query */
  2225. /* 2 : LOCK */
  2226. /* -2 : UNLOCK */
  2227. void* structcheck_init(int init) {
  2228.   int structcheck_size = 1024;
  2229.   inthash structcheck_hash=NULL;
  2230.   /* */
  2231.   static PTHREAD_LOCK_TYPE structcheck_init_mutex;
  2232.   static int structcheck_init_mutex_init=0;
  2233.  
  2234.   if (init == 1 || init == -1) {
  2235.     if (init) {
  2236.       if (structcheck_hash)
  2237.         inthash_delete(&structcheck_hash);
  2238.       structcheck_hash=NULL;
  2239.     }
  2240.     if (init != -1) {
  2241.       if (structcheck_init_mutex_init == 0) {
  2242.         htsSetLock(&structcheck_init_mutex, -999);
  2243.         structcheck_init_mutex_init=1;
  2244.       }
  2245.       if (structcheck_hash==NULL) {
  2246.         structcheck_hash=inthash_new(structcheck_size);  // dΘsallouΘ xh_xx
  2247.       }
  2248.     }
  2249.   }
  2250.  
  2251.   /* Lock / Unlock */
  2252.   if (init == 2) {  // Lock
  2253.     htsSetLock(&structcheck_init_mutex, 1);
  2254.   } else if (init == -2) {  // Unlock
  2255.     htsSetLock(&structcheck_init_mutex, 0);
  2256.   }
  2257.   return structcheck_hash;
  2258. }
  2259. #endif
  2260.  
  2261. int filters_init(char*** ptrfilters, int maxfilter, int filterinc) {
  2262.   char** filters = *ptrfilters;
  2263.   int filter_max=maximum(maxfilter, 128);
  2264.   if (filters == NULL) {
  2265.     filters=(char**) malloct( sizeof(char*) * (filter_max+2) );
  2266.     memset(filters, 0, sizeof(char*) * (filter_max+2));  // filters[0] == 0
  2267.   } else {
  2268.     filters=(char**) realloct(filters, sizeof(char*) * (filter_max+2) );
  2269.   }
  2270.   if (filters) {
  2271.     if (filters[0] == NULL) {
  2272.       filters[0]=(char*) malloct( sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
  2273.       memset(filters[0], 0, sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
  2274.     } else {
  2275.       filters[0]=(char*) realloct(filters[0], sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
  2276.     }
  2277.     if (filters[0] == NULL) {
  2278.       freet(filters);
  2279.       filters = NULL;
  2280.     }
  2281.   }
  2282.   if (filters != NULL) {
  2283.     int i;
  2284.     int from;
  2285.     if (filterinc == 0)
  2286.       from = 0;
  2287.     else
  2288.       from = filter_max - filterinc;
  2289.     for(i=0 ; i<=filter_max ; i++) {    // PLUS UN (sΘcuritΘ)
  2290.       filters[i]=filters[0]+i*(HTS_URLMAXSIZE*2);
  2291.     }
  2292.     for(i=from ; i<=filter_max ; i++) {    // PLUS UN (sΘcuritΘ)
  2293.       filters[i][0]='\0';    // clear
  2294.     }
  2295.   }
  2296.   *ptrfilters = filters;
  2297.   return (filters != NULL) ? filter_max : 0;
  2298. }
  2299.  
  2300. // vΘrifier prΘsence de l'arbo
  2301. HTSEXT_API int structcheck(char* s) {
  2302.   // vΘrifier la prΘsence des dossier(s)
  2303.   char *a=s;
  2304.   char nom[HTS_URLMAXSIZE*2];
  2305.   char *b;
  2306.   //inthash structcheck_hash=NULL;
  2307.   if (strnotempty(s)==0) return 0;
  2308.   if (strlen(s)>HTS_URLMAXSIZE) return 0;
  2309.  
  2310.   // Get buffer address
  2311.   /*
  2312.   structcheck_hash = (inthash)structcheck_init(0);
  2313.   if (structcheck_hash == NULL) {
  2314.     return -1;
  2315.   }
  2316.   */
  2317.  
  2318.   b=nom;
  2319.   do {    
  2320.     if (*a) *b++=*a++;
  2321.     while((*a!='/') && (*a!='\0')) *b++=*a++;
  2322.     *b='\0';    // pas de ++ pour boucler
  2323.     if (*a=='/') {    // toujours dossier
  2324.       if (strnotempty(nom)) {         
  2325.         //if (inthash_write(structcheck_hash, nom, 1)) {    // non encore crΘΘ                       
  2326. #if HTS_WIN
  2327.         if (mkdir(fconv(nom))!=0)
  2328. #else    
  2329.           if (mkdir(fconv(nom),HTS_ACCESS_FOLDER)!=0)
  2330. #endif
  2331.           {
  2332. #if HTS_REMOVE_ANNOYING_INDEX
  2333.             // might be a filename with same name than this folder
  2334.             // then, remove it to allow folder creation
  2335.             // it happends when servers gives a folder index while
  2336.             // requesting / page
  2337.             // -> if the file can be opened (not a folder) then rename it
  2338.             if (fexist(fconv(nom))) {
  2339.               rename(fconv(nom),fconcat(fconv(nom),".txt"));
  2340.             }
  2341.             // if it fails, that's too bad
  2342. #if HTS_WIN
  2343.             mkdir(fconv(nom));
  2344. #else    
  2345.             mkdir(fconv(nom),HTS_ACCESS_FOLDER);
  2346. #endif
  2347. #endif
  2348.             // Si existe dΘja renvoie une erreur.. tant pis
  2349.           }
  2350. #if HTS_WIN==0
  2351.           /*chmod(fconv(nom),HTS_ACCESS_FOLDER);*/
  2352. #endif
  2353.           //}
  2354.       }
  2355.       *b++=*a++;    // slash
  2356.     } 
  2357.   } while(*a);
  2358.   return 0;
  2359. }
  2360.  
  2361.  
  2362. // sauver un fichier
  2363. int filesave(httrackp* opt,char* adr,int len,char* s,char* url_adr,char* url_fil) {
  2364.   FILE* fp;
  2365.   // Θcrire le fichier
  2366.   if ((fp=filecreate(s))!=NULL) {
  2367.     int nl=0;
  2368.     if (len>0) {
  2369.       nl=(int) fwrite(adr,1,(INTsys)len,fp);
  2370.     }
  2371.     fclose(fp);
  2372.     //xxusercommand(opt,0,NULL,fconv(s),url_adr,url_fil);
  2373.     if (nl!=len)  // erreur
  2374.       return -1;
  2375.   } else
  2376.     return -1;
  2377.   
  2378.   return 0;
  2379. }
  2380.  
  2381. /* We should stop */
  2382. int check_fatal_io_errno(void) {
  2383.   switch(errno) {
  2384. #ifdef EMFILE
  2385.   case EMFILE: /* Too many open files */
  2386. #endif
  2387. #ifdef ENOSPC
  2388.   case ENOSPC: /* No space left on device */
  2389. #endif
  2390. #ifdef EROFS
  2391.   case EROFS:  /* Read-only file system */
  2392. #endif
  2393.     return 1;
  2394.     break;
  2395.   }
  2396.   return 0;
  2397. }
  2398.  
  2399.  
  2400. // ouvrir un fichier (avec chemin Un*x)
  2401. FILE* filecreate(char* s) {
  2402.   char fname[HTS_URLMAXSIZE*2];
  2403.   FILE* fp;
  2404.   fname[0]='\0';
  2405.  
  2406.   // noter lst
  2407.   filenote(s,NULL);
  2408.   
  2409.   // if (*s=='/') strcpybuff(fname,s+1); else strcpybuff(fname,s);    // pas de / (root!!) // ** SIIIIIII!!! α cause de -O <path>
  2410.   strcpybuff(fname,s);
  2411.  
  2412. #if HTS_DOSNAME
  2413.   // remplacer / par des slash arriΦre
  2414.   {
  2415.     int i=0;
  2416.     while(fname[i]) {
  2417.       if (fname[i]=='/')
  2418.         fname[i]='\\';
  2419.       i++;
  2420.     } 
  2421.   } 
  2422.   // a partir d'ici le slash devient antislash
  2423. #endif
  2424.   
  2425.   // ouvrir
  2426.   fp=fopen(fname,"wb");
  2427.   if (fp == NULL) {
  2428.     // construire le chemin si besoin est
  2429.     (void)structcheck(s);
  2430.     fp=fopen(fname,"wb");
  2431.   }
  2432.   
  2433. #if HTS_WIN==0
  2434.   if (fp!=NULL) chmod(fname,HTS_ACCESS_FILE);
  2435. #endif
  2436.  
  2437.   return fp;
  2438. }
  2439.  
  2440. // create an empty file
  2441. int filecreateempty(char* filename) {
  2442.   FILE* fp;
  2443.   fp=filecreate(filename);      // filenote & co
  2444.   if (fp) {
  2445.     fclose(fp);
  2446.     return 1;
  2447.   } else
  2448.     return 0; 
  2449. }
  2450.  
  2451. // noter fichier
  2452. typedef struct {
  2453.   FILE* lst;
  2454.   char path[HTS_URLMAXSIZE*2];
  2455. } filenote_strc;
  2456. int filenote(char* s,filecreate_params* params) {
  2457.   filenote_strc* strc;
  2458.   NOSTATIC_RESERVE(strc, filenote_strc, 1);
  2459.   
  2460.   // gestion du fichier liste liste
  2461.   if (params) {
  2462.     //filecreate_params* p = (filecreate_params*) params;
  2463.     strcpybuff(strc->path,params->path);
  2464.     strc->lst=params->lst;
  2465.     return 0;
  2466.   } else if (strc->lst) {
  2467.     char savelst[HTS_URLMAXSIZE*2];
  2468.     strcpybuff(savelst,fslash(s));
  2469.     // couper chemin?
  2470.     if (strnotempty(strc->path)) {
  2471.       if (strncmp(fslash(strc->path),savelst,strlen(strc->path))==0) {  // couper
  2472.         strcpybuff(savelst,s+strlen(strc->path));
  2473.       }
  2474.     }
  2475.     fprintf(strc->lst,"[%s]"LF,savelst);
  2476.     fflush(strc->lst);
  2477.   }
  2478.   return 1;
  2479. }
  2480.  
  2481. // executer commande utilisateur
  2482. static void postprocess_file(httrackp* opt,char* save, char* adr, char* fil);
  2483. typedef struct {
  2484.   int exe;
  2485.   char cmd[2048];
  2486. } usercommand_strc;
  2487. HTS_INLINE void usercommand(httrackp* opt,int _exe,char* _cmd,char* file,char* adr,char* fil) {
  2488.   usercommand_strc* strc;
  2489.   NOSTATIC_RESERVE(strc, usercommand_strc, 1);
  2490.   
  2491.   /* Callback */
  2492.   if (_exe) {
  2493.     strcpybuff(strc->cmd,_cmd);
  2494.     if (strnotempty(strc->cmd))
  2495.       strc->exe=_exe;
  2496.     else
  2497.       strc->exe=0;
  2498.   }
  2499.  
  2500.   /* post-processing */
  2501.   postprocess_file(opt, file, adr, fil);
  2502.  
  2503. #if HTS_ANALYSTE
  2504.   if (hts_htmlcheck_filesave != NULL)
  2505.   if (file != NULL && strnotempty(file))
  2506.     hts_htmlcheck_filesave(file);
  2507. #endif
  2508.  
  2509.   if (strc->exe) {
  2510.     if (file != NULL && strnotempty(file)) {
  2511.       if (strnotempty(strc->cmd)) {
  2512.         usercommand_exe(strc->cmd,file);
  2513.       }
  2514.     }
  2515.   }
  2516. }
  2517. void usercommand_exe(char* cmd,char* file) {
  2518.   char temp[8192];
  2519.   char c[2]="";
  2520.   int i;
  2521.   temp[0]='\0';
  2522.   //
  2523.   for(i=0;i<(int) strlen(cmd);i++) {
  2524.     if ((cmd[i]=='$') && (cmd[i+1]=='0')) {
  2525.       strcatbuff(temp,file);
  2526.       i++;
  2527.     } else {
  2528.       c[0]=cmd[i]; c[1]='\0';
  2529.       strcatbuff(temp,c);
  2530.     }
  2531.   }
  2532.   system(temp);
  2533. }
  2534.  
  2535.  
  2536. static void postprocess_file(httrackp* opt,char* save, char* adr, char* fil) {
  2537.   int first = 0;
  2538.   /* MIME-html archive to build */
  2539.   if (opt != NULL && opt->mimehtml) {
  2540.     if (adr != NULL && strcmp(adr, "primary") == 0) {
  2541.       adr = NULL;
  2542.     }
  2543.     if (save != NULL && opt != NULL && adr != NULL && adr[0] && strnotempty(save) && fexist(save)) {
  2544.       char* rsc_save = save;
  2545.       char* rsc_fil = strrchr(fil, '/');
  2546.       int n;
  2547.       if (rsc_fil == NULL)
  2548.         rsc_fil = fil;
  2549.       if (strncmp(fslash(save), fslash(opt->path_html), (n = (int)strlen(opt->path_html))) == 0) {
  2550.         rsc_save += n;
  2551.       }
  2552.  
  2553.       if (!opt->state.mimehtml_created) {
  2554.         first = 1;
  2555.         opt->state.mimefp = fopen(fconcat(opt->path_html,"index.mht"), "wb");
  2556.         if (opt->state.mimefp != NULL) {
  2557.           char rndtmp[1024], currtime[256];
  2558.           srand(time(NULL));
  2559.           time_gmt_rfc822(currtime);
  2560.           sprintf(rndtmp, "%d_%d", (int)time(NULL), (int) rand());
  2561.           sprintf(opt->state.mimemid, "----=_MIMEPart_%s_=----", rndtmp);
  2562.           fprintf(opt->state.mimefp, "From: HTTrack Website Copier <nobody@localhost>\r\n"
  2563.             "Subject: Local mirror\r\n"
  2564.             "Date: %s\r\n"
  2565.             "Message-ID: <httrack_%s@localhost>\r\n"
  2566.             "Content-Type: multipart/related;\r\n"
  2567.             "\tboundary=\"%s\";\r\n"
  2568.             "\ttype=\"text/html\"\r\n"
  2569.             "MIME-Version: 1.0\r\n"
  2570.             "\r\nThis message is a RFC MIME-compliant multipart message.\r\n"
  2571.             "\r\n"
  2572.             , currtime, rndtmp, opt->state.mimemid);
  2573.           opt->state.mimehtml_created = 1;
  2574.         } else {
  2575.           opt->state.mimehtml_created = -1;
  2576.           if ( opt->errlog != NULL ) {
  2577.             fspc(opt->errlog,"error"); fprintf(opt->log,"unable to create index.mht"LF);
  2578.           }
  2579.         }
  2580.       }
  2581.       if (opt->state.mimehtml_created == 1 && opt->state.mimefp != NULL) {
  2582.         FILE* fp = fopen(save, "rb");
  2583.         if (fp != NULL) {
  2584.           char buff[60*100 + 2];
  2585.           char mimebuff[256];
  2586.           char cid[HTS_URLMAXSIZE*3];
  2587.           int len;
  2588.           int isHtml = ( ishtml(save) == 1 );
  2589.           mimebuff[0] = '\0';
  2590.  
  2591.           /* CID */
  2592.           strcpybuff(cid, adr);
  2593.           strcatbuff(cid, fil);
  2594.           escape_in_url(cid);
  2595.           { char* a = cid; while((a = strchr(a, '%'))) { *a = 'X'; a++; } }
  2596.           
  2597.           guess_httptype(mimebuff, save);
  2598.           fprintf(opt->state.mimefp, "--%s\r\n", opt->state.mimemid);
  2599.           /*if (first)
  2600.           fprintf(opt->state.mimefp, "Content-disposition: inline\r\n");
  2601.           else*/
  2602.           fprintf(opt->state.mimefp, "Content-disposition: attachment; filename=\"%s\"\r\n", rsc_save);
  2603.           fprintf(opt->state.mimefp, 
  2604.             "Content-Type: %s\r\n"
  2605.             "Content-Transfer-Encoding: %s\r\n"
  2606.             /*"Content-Location: http://localhost/%s\r\n"*/
  2607.             "Content-ID: <%s>\r\n"
  2608.             "\r\n"
  2609.             , mimebuff
  2610.             , isHtml ? "8bit" : "base64"
  2611.             /*, rsc_save*/
  2612.             , cid);
  2613.           while((len = fread(buff, 1, sizeof(buff) - 2, fp)) > 0) {
  2614.             buff[len] = '\0';
  2615.             if (!isHtml) {
  2616.               char base64buff[60*100*2];
  2617.               code64((unsigned char*)buff, len, (unsigned char*)base64buff, 1);
  2618.               fprintf(opt->state.mimefp, "%s", base64buff);
  2619.             } else {
  2620.               fprintf(opt->state.mimefp, "%s", buff);
  2621.             }
  2622.           }
  2623.           fclose(fp);
  2624.           fprintf(opt->state.mimefp, "\r\n\r\n");
  2625.         }
  2626.       }
  2627.     } else if (save == NULL) {
  2628.       if (opt->state.mimehtml_created == 1 && opt->state.mimefp != NULL) {
  2629.         fprintf(opt->state.mimefp, 
  2630.           "--%s--\r\n", opt->state.mimemid);
  2631.         fclose(opt->state.mimefp);
  2632.         opt->state.mimefp = NULL;
  2633.       }
  2634.     }
  2635.   }
  2636. }
  2637.  
  2638. // Θcrire n espaces dans fp
  2639. typedef struct {
  2640.   int error;
  2641.   int warning;
  2642.   int info;
  2643. } fspc_strc;
  2644. HTS_INLINE int fspc(FILE* fp,char* type) {
  2645.   fspc_strc* strc;
  2646.   NOSTATIC_RESERVE(strc, fspc_strc, 1); // log..
  2647.  
  2648.   //
  2649.   if (fp) {
  2650.     char s[256];
  2651.     time_t tt;
  2652.     struct tm* A;
  2653.     tt=time(NULL);
  2654.     A=localtime(&tt);
  2655.     if (A == NULL) {
  2656.       int localtime_returned_null=0;
  2657.       assert(localtime_returned_null);
  2658.     }
  2659.     strftime(s,250,"%H:%M:%S",A);
  2660.     if (strnotempty(type))
  2661.       fprintf(fp,"%s\t%c%s: \t",s,hichar(*type),type+1);
  2662.     else
  2663.       fprintf(fp,"%s\t \t",s);
  2664.     if (strcmp(type,"warning")==0)
  2665.       strc->warning++;
  2666.     else if (strcmp(type,"error")==0)
  2667.       strc->error++;
  2668.     else if (strcmp(type,"info")==0)
  2669.       strc->info++;
  2670.   } 
  2671.   else if (!type)
  2672.     strc->error=strc->warning=strc->info=0;     // reset
  2673.   else if (strcmp(type,"warning")==0)
  2674.     return strc->warning;
  2675.   else if (strcmp(type,"error")==0)
  2676.     return strc->error;
  2677.   else if (strcmp(type,"info")==0)
  2678.     return strc->info;
  2679.   return 0;
  2680. }
  2681.  
  2682.  
  2683. // vΘrifier taux de transfert
  2684. #if 0
  2685. void check_rate(TStamp stat_timestart,int maxrate) {
  2686.   // vΘrifier taux de transfert (pas trop grand?)
  2687.   /*
  2688.   if (maxrate>0) {
  2689.     int r = (int) (HTS_STAT.HTS_TOTAL_RECV/(time_local()-stat_timestart));    // taux actuel de transfert
  2690.     HTS_STAT.HTS_TOTAL_RECV_STATE=0;
  2691.     if (r>maxrate) {    // taux>taux autorisΘ
  2692.       int taux = (int) (((TStamp) (r - maxrate) * 100) / (TStamp) maxrate);
  2693.       if (taux<15)
  2694.         HTS_STAT.HTS_TOTAL_RECV_STATE=1;   // ralentir un peu (<15% dΘpassement)
  2695.       else if (taux<50)
  2696.         HTS_STAT.HTS_TOTAL_RECV_STATE=2;   // beaucoup (<50% dΘpassement)
  2697.       else
  2698.         HTS_STAT.HTS_TOTAL_RECV_STATE=3;   // ΘnormΘment (>50% dΘpassement)
  2699.     }
  2700.   }
  2701.   */
  2702. }
  2703. #endif
  2704.  
  2705. // ---
  2706. // sous routines liΘes au moteur et au backing
  2707.  
  2708. // supplemental links ready (done) after ptr
  2709. int backlinks_done(lien_url** liens,int lien_tot,int ptr) {
  2710.   int n=0;
  2711.   int i;
  2712.   //Links done and stored in cache
  2713.   for(i=ptr+1;i<lien_tot;i++) {
  2714.     if (liens[i]) {
  2715.       if (liens[i]->pass2 == -1) {
  2716.         n++;
  2717.       }
  2718.     }
  2719.   }
  2720.   return n;
  2721. }
  2722.  
  2723. // remplir backing si moins de max_bytes en mΘmoire
  2724. HTS_INLINE int back_fillmax(lien_back* back,int back_max,httrackp* opt,cache_back* cache,lien_url** liens,int ptr,int numero_passe,int lien_tot) {
  2725.   if (!opt->state.stop) {
  2726.     if (back_incache(back,back_max)<opt->maxcache) {  // pas trop en mΘmoire?
  2727.       return back_fill(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot);
  2728.     }
  2729.   }
  2730.   return -1;                /* plus de place */
  2731. }
  2732.  
  2733. // remplir backing
  2734. int back_fill(lien_back* back,int back_max,httrackp* opt,cache_back* cache,lien_url** liens,int ptr,int numero_passe,int lien_tot) {
  2735.   int n;
  2736.   int oneLess = ( (_hts_in_html_parsing == 2 && opt->maxsoc >= 2) || (_hts_in_html_parsing == 1 && opt->maxsoc >= 4) ) ? 1 : 0;  // testing links
  2737.  
  2738.   // ajouter autant de socket qu'on peut ajouter
  2739.   n=opt->maxsoc-back_nsoc(back,back_max) - oneLess;
  2740.  
  2741.   // vΘrifier qu'il restera assez de place pour les tests ensuite (en thΘorie, 1 entrΘe libre restante suffirait)
  2742.   n=min( n, back_available(back,back_max) - 8 );
  2743.  
  2744.   // no space left on backing stack - do not back anymore
  2745.   if (back_stack_available(back,back_max) <= 2)
  2746.     n=0;
  2747.  
  2748.   if (n>0) {
  2749.     int p;
  2750.  
  2751.     if (ptr<cache->ptr_last) {      /* restart (2 scans: first html, then non html) */
  2752.       cache->ptr_ant=0;
  2753.     }
  2754.  
  2755.     p=ptr+1;
  2756.     /* on a dΘja parcouru */
  2757.     if (p<cache->ptr_ant)
  2758.       p=cache->ptr_ant;
  2759.     while( (p<lien_tot) && (n>0) && back_checkmirror(opt)) {
  2760.     //while((p<lien_tot) && (n>0) && (p < ptr+opt->maxcache_anticipate)) {
  2761.       int ok=1;
  2762.       
  2763.       // on ne met pas le fichier en backing si il doit Ωtre traitΘ aprΦs
  2764.       if (liens[p]->pass2) {  // 2Φ passe
  2765.         if (numero_passe!=1)
  2766.           ok=0;
  2767.       } else {
  2768.         if (numero_passe!=0)
  2769.           ok=0;
  2770.       }
  2771.       
  2772.       // note: si un backing est fini, il reste en mΘmoire jusqu'α ce que
  2773.       // le ptr l'atteigne
  2774.       if (ok) {
  2775.         if (!back_exist(back,back_max,liens[p]->adr,liens[p]->fil,liens[p]->sav)) {
  2776.           if (back_add(back,back_max,opt,cache,liens[p]->adr,liens[p]->fil,liens[p]->sav,liens[liens[p]->precedent]->adr,liens[liens[p]->precedent]->fil,liens[p]->testmode,&liens[p]->pass2)==-1) {
  2777.             if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  2778.               fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: unable to add more links through back_add for back_fill"LF);
  2779.               test_flush;
  2780.             }                    
  2781. #if BDEBUG==1
  2782.             printf("error while adding\n");
  2783. #endif                  
  2784.             n=0;    // sortir
  2785.           } else {
  2786.             n--;
  2787. #if BDEBUG==1
  2788.             printf("backing: %s%s\n",liens[p]->adr,liens[p]->fil);          
  2789. #endif
  2790.           } 
  2791.         }
  2792.       }
  2793.       p++;
  2794.     }  // while
  2795.     /* sauver position derniΦre anticipation */
  2796.     cache->ptr_ant=p;
  2797.     cache->ptr_last=ptr;
  2798.   }
  2799.   return 0;
  2800. }
  2801. // ---
  2802.  
  2803.  
  2804.  
  2805.  
  2806.  
  2807.  
  2808.  
  2809.  
  2810.  
  2811.  
  2812.  
  2813.  
  2814.  
  2815.  
  2816.  
  2817.  
  2818.  
  2819.  
  2820. // routines de dΘtournement de SIGHUP & co (Unix)
  2821. //
  2822. httrackp* hts_declareoptbuffer(httrackp* optdecl) {
  2823.   static httrackp* opt=NULL; /* OK */
  2824.   if (optdecl) opt=optdecl;
  2825.   return opt;
  2826. }
  2827. //
  2828. void sig_finish( int code ) {       // finir et quitter
  2829.   signal(code,sig_term);  // quitter si encore
  2830.   exit_xh=1;
  2831.   fprintf(stderr,"\nExit requested to engine (signal %d)\n",code);
  2832. }
  2833. void sig_term( int code ) {       // quitter brutalement
  2834.   fprintf(stderr,"\nProgram terminated (signal %d)\n",code);
  2835.   exit(0);
  2836. }
  2837. #if HTS_WIN
  2838. void sig_ask( int code ) {        // demander
  2839.   char s[256];
  2840.   signal(code,sig_term);  // quitter si encore
  2841.   printf("\nQuit program/Interrupt/Cancel? (Q/I/C) ");
  2842.   fflush(stdout);
  2843.   scanf("%s",s);
  2844.   if ( (s[0]=='y') || (s[0]=='Y') || (s[0]=='o') || (s[0]=='O') || (s[0]=='q') || (s[0]=='Q'))
  2845.     exit(0);     // quitter
  2846.   else if ( (s[0]=='i') || (s[0]=='I') ) {
  2847.     httrackp* opt=hts_declareoptbuffer(NULL);
  2848.     if (opt) {
  2849.       // ask for stop
  2850.       opt->state.stop=1;
  2851.     }
  2852.   }
  2853.   signal(code,sig_ask);  // remettre signal
  2854. }
  2855. #else
  2856. void sig_back( int code ) {       // ignorer et mettre en backing 
  2857.   signal(code,sig_ignore);
  2858.   sig_doback(0);
  2859. }
  2860. void sig_ask( int code ) {        // demander
  2861.   char s[256];
  2862.   signal(code,sig_term);  // quitter si encore
  2863.   printf("\nQuit program/Interrupt/Background/bLind background/Cancel? (Q/I/B/L/C) ");
  2864.   fflush(stdout);
  2865.   scanf("%s",s);
  2866.   if ( (s[0]=='y') || (s[0]=='Y') || (s[0]=='o') || (s[0]=='O') || (s[0]=='q') || (s[0]=='Q'))
  2867.     exit(0);     // quitter
  2868.   else if ( (s[0]=='b') || (s[0]=='B') || (s[0]=='a') || (s[0]=='A') )
  2869.     sig_doback(0);  // arriΦre plan
  2870.   else if ( (s[0]=='l') || (s[0]=='L') )
  2871.     sig_doback(1);  // arriΦre plan
  2872.   else if ( (s[0]=='i') || (s[0]=='I') ) {
  2873.     httrackp* opt=hts_declareoptbuffer(NULL);
  2874.     if (opt) {
  2875.       // ask for stop
  2876.       printf("finishing pending transfers.. please wait\n");
  2877.       opt->state.stop=1;
  2878.     }
  2879.     signal(code,sig_ask);  // remettre signal
  2880.   }
  2881.   else {
  2882.     printf("cancel..\n");
  2883.     signal(code,sig_ask);  // remettre signal
  2884.   }
  2885. }
  2886. void sig_ignore( int code ) {     // ignorer signal
  2887. }
  2888. void sig_brpipe( int code ) {     // treat if necessary
  2889.   /*
  2890.   if (!sig_ignore_flag(-1)) {
  2891.     sig_term(code);
  2892.   }
  2893.   */
  2894. }
  2895. void sig_doback(int blind) {       // mettre en backing 
  2896.   int out=-1;
  2897.   //
  2898.   printf("\nMoving into background to complete the mirror...\n"); fflush(stdout);
  2899.  
  2900.   {
  2901.     httrackp* opt=hts_declareoptbuffer(NULL);
  2902.     if (opt) {
  2903.       // suppress logging and asking lousy questions
  2904.       opt->quiet=1;
  2905.       opt->verbosedisplay=0;
  2906.     }
  2907.   }
  2908.  
  2909.   if (!blind)
  2910.     out = open("hts-nohup.out",O_CREAT|O_WRONLY,S_IRUSR|S_IWUSR);
  2911.   if (out == -1)
  2912.     out = open("/dev/null",O_WRONLY,S_IRUSR|S_IWUSR);
  2913.   close(0);
  2914.   close(1);
  2915.   dup(out);
  2916.   close(2);
  2917.   dup(out);
  2918.   //
  2919.   switch (fork()) {
  2920.   case 0: 
  2921.     break;
  2922.   case -1:
  2923.     fprintf(stderr,"Error: can not fork process\n");
  2924.     break;
  2925.   default:            // pere
  2926.     usleep(100000);   // pause 1/10s "A  microsecond  is  .000001s"
  2927.     _exit(0);
  2928.     break;  
  2929.   }
  2930. }
  2931. #endif
  2932. // fin routines de dΘtournement de SIGHUP & co
  2933.  
  2934. // Poll stdin.. si besoin
  2935. #if HTS_POLL
  2936. // lecture stdin des caractΦres disponibles
  2937. int read_stdin(char* s,int max) {
  2938.   int i=0;
  2939.   while((check_stdin()) && (i<(max-1)) )
  2940.     s[i++]=fgetc(stdin);
  2941.   s[i]='\0';
  2942.   return i;
  2943. }
  2944. #ifdef _WIN32
  2945. HTS_INLINE int check_stdin(void) {
  2946.   return (_kbhit());
  2947. }
  2948. #else
  2949. HTS_INLINE int check_flot(T_SOC s) {
  2950.   fd_set fds;
  2951.   struct timeval tv;
  2952.   FD_ZERO(&fds);
  2953.   FD_SET((T_SOC) s,&fds);
  2954.   tv.tv_sec=0;
  2955.   tv.tv_usec=0;
  2956.   select(s+1,&fds,NULL,NULL,&tv);
  2957.   return FD_ISSET(s,&fds);
  2958. }
  2959. HTS_INLINE int check_stdin(void) {
  2960.   fflush(stdout); fflush(stdin);
  2961.   if (check_flot(0))
  2962.     return 1;
  2963.   return 0;
  2964. }
  2965. #endif
  2966. #endif
  2967.  
  2968. HTS_INLINE int check_sockerror(T_SOC s) {
  2969.   fd_set fds;
  2970.   struct timeval tv;
  2971.   FD_ZERO(&fds);
  2972.   FD_SET((T_SOC) s,&fds);
  2973.   tv.tv_sec=0;
  2974.   tv.tv_usec=0;
  2975.   select(s+1,NULL,NULL,&fds,&tv);
  2976.   return FD_ISSET(s,&fds);
  2977. }
  2978.  
  2979. /* check incoming data */
  2980. HTS_INLINE int check_sockdata(T_SOC s) {
  2981.   fd_set fds;
  2982.   struct timeval tv;
  2983.   FD_ZERO(&fds);
  2984.   FD_SET((T_SOC) s,&fds);
  2985.   tv.tv_sec=0;
  2986.   tv.tv_usec=0;
  2987.   select(s+1,&fds,NULL,NULL,&tv);
  2988.   return FD_ISSET(s,&fds);
  2989. }
  2990.  
  2991. // Attente de touche
  2992. #if HTS_ANALYSTE
  2993. int ask_continue(void) {
  2994.   char* s;
  2995.   s=hts_htmlcheck_query2(HTbuff);
  2996.   if (s) {
  2997.     if (strnotempty(s)) {
  2998.       if ((strfield2(s,"N")) || (strfield2(s,"NO")) || (strfield2(s,"NON")))
  2999.         return 0;
  3000.     }
  3001.     return 1;
  3002.   }
  3003.   return 1;
  3004. }
  3005. #else
  3006. int ask_continue(void) {
  3007.   char s[12];
  3008.   s[0]='\0';
  3009.   printf("Press <Y><Enter> to confirm, <N><Enter> to abort\n");
  3010.   io_flush; linput(stdin,s,4);
  3011.   if (strnotempty(s)) {
  3012.     if ((strfield2(s,"N")) || (strfield2(s,"NO")) || (strfield2(s,"NON")))
  3013.       return 0;
  3014.   }
  3015.   return 1;
  3016. }
  3017. #endif
  3018.  
  3019. // nombre de digits dans un nombre
  3020. int nombre_digit(int n) {
  3021.   int i=1;
  3022.   while(n >= 10) { n/=10; i++; }
  3023.   return i;
  3024. }
  3025.  
  3026.  
  3027. // renvoi adresse de la fin du token dans p
  3028. // renvoi NULL si la chaine est un token unique
  3029. // (PATCHE Θgalement la chaine)
  3030. // ex: "test" "test2" renvoi adresse sur espace
  3031. // flag==1 si chaine comporte des echappements comme \"
  3032. char* next_token(char* p,int flag) {
  3033.   int detect=0;
  3034.   int quote=0;
  3035.   p--;
  3036.   do {
  3037.     p++;
  3038.     if (flag && (*p=='\\')) {   // sauter \x ou \"
  3039.       if (quote) {
  3040.         char c='\0';
  3041.         if (*(p+1)=='\\')
  3042.           c='\\';
  3043.         else if (*(p+1)=='"')
  3044.           c='"';
  3045.         if (c) {
  3046.           char tempo[8192];
  3047.           tempo[0]=c; tempo[1]='\0';
  3048.           strcatbuff(tempo,p+2);
  3049.           strcpybuff(p,tempo);
  3050.         }
  3051.       }
  3052.     }
  3053.     else if (*p==34) {  // guillemets (de fin)
  3054.       char tempo[8192];
  3055.       tempo[0]='\0';
  3056.       strcatbuff(tempo,p+1);
  3057.       strcpybuff(p,tempo);   /* wipe "" */
  3058.       p--;
  3059.       /* */
  3060.       quote=!quote;
  3061.     }
  3062.     else if (*p==32) {
  3063.       if (!quote)
  3064.         detect=1;
  3065.     }
  3066.     else if (*p=='\0') {
  3067.       p=NULL;
  3068.       detect=1;
  3069.     }
  3070.   } while(!detect);
  3071.   return p;
  3072. }
  3073.  
  3074. // routines annexes 
  3075. #if HTS_ANALYSTE
  3076. // canceller un fichier (noter comme cancellable)
  3077. // !!NOT THREAD SAFE!!
  3078. HTSEXT_API char* hts_cancel_file(char * s) {
  3079.   static char sav[HTS_URLMAXSIZE*2]="";
  3080.   if (s[0]!='\0')
  3081.   if (sav[0]=='\0')
  3082.     strcpybuff(sav,s);
  3083.   return sav;
  3084. }
  3085. HTSEXT_API void hts_cancel_test(void) {
  3086.   if (_hts_in_html_parsing==2)
  3087.     _hts_cancel=2;
  3088. }
  3089. HTSEXT_API void hts_cancel_parsing(void) {
  3090.   if (_hts_in_html_parsing)
  3091.    _hts_cancel=1;
  3092. }
  3093. #endif
  3094. //        for(_i=0;(_i<back_max) && (index<NStatsBuffer);_i++) {
  3095. //          i=(back_index+_i)%back_max;    // commencer par le "premier" (l'actuel)
  3096. //          if (back[i].status>=0) {     // signifie "lien actif"
  3097.  
  3098. #if 0
  3099. /*  
  3100. hts_add_file, add/get elements in the add chain for java parsing
  3101. if file_position >= 0
  3102.   push 'file/file_position'
  3103.   return 1 (return 0 if exists)
  3104. else
  3105.   pop file -> 'file'
  3106.   return 'file_position'
  3107. else if empty/error
  3108.   return -1;
  3109. */
  3110. typedef struct addfile_chain {
  3111.   char name[1024];
  3112.   int pos;
  3113.   struct addfile_chain* next;
  3114. } addfile_chain;
  3115. typedef addfile_chain* addfile_chain_ptr;
  3116. int opt->(char* file,int file_position) {
  3117.   addfile_chain** chain;
  3118.   NOSTATIC_RESERVE(chain, addfile_chain_ptr, 1);
  3119.  
  3120.   if (file_position>=0) {         /* copy file to the chain */
  3121.     struct addfile_chain** current;
  3122.     current=chain;                     /* start from */
  3123.     while(*current) {
  3124.       if (strcmp((*current)->name,file)==0)
  3125.         return 0;                       /* already exists */
  3126.       current=&( (*current)->next );    /* 'next' address */
  3127.     }
  3128.     *current=calloct(1,sizeof(addfile_chain));
  3129.     if (*current) {
  3130.       (*current)->next=NULL;
  3131.       (*current)->pos=-1;
  3132.       (*current)->name[0]='\0';
  3133.     }
  3134.     if (*current) {
  3135.       strcpybuff((*current)->name,file);
  3136.       (*current)->pos=file_position;
  3137.       return 1;
  3138.     } else {
  3139.       printf("PANIC! Too many Java files during parsing [1]\n");
  3140.       return -1;
  3141.     }
  3142.   } else {                      /* copy last element in file and delete it */
  3143.     if (file)
  3144.       file[0]='\0';
  3145.     if (*chain) {
  3146.       struct addfile_chain** current;
  3147.       int pos=-1;
  3148.       current=chain;                     /* start from */
  3149.       while( (*current)->next ) {
  3150.         current=&( (*current)->next );    /* 'next' address */
  3151.       }
  3152.       if (file)
  3153.         strcpybuff(file,(*current)->name);
  3154.       pos=(*current)->pos;
  3155.       freet(*current);
  3156.       *current=NULL;
  3157.       return pos;
  3158.     }
  3159.     return -1;                            /* no more elements */
  3160.   }
  3161.  
  3162.   return 0;
  3163. }
  3164. #endif
  3165.  
  3166. #if HTS_ANALYSTE
  3167. // en train de parser un fichier html? rΘponse: % effectuΘs
  3168. // flag>0 : refresh demandΘ
  3169. HTSEXT_API int hts_is_parsing(int flag) {
  3170.   if (_hts_in_html_parsing) {  // parsing?
  3171.     if (flag>=0) _hts_in_html_poll=1;  // faudrait un tit refresh
  3172.     return max(_hts_in_html_done,1); // % effectuΘs
  3173.   } else {
  3174.     return 0;                 // non
  3175.   }
  3176. }
  3177. HTSEXT_API int hts_is_testing(void) {            // 0 non 1 test 2 purge
  3178.   if (_hts_in_html_parsing==2)
  3179.     return 1;
  3180.   else if (_hts_in_html_parsing==3)
  3181.     return 2;
  3182.   else if (_hts_in_html_parsing==4)
  3183.     return 3;
  3184.   return 0;
  3185. }
  3186. HTSEXT_API int hts_is_exiting(void) {
  3187.   return exit_xh;
  3188. }
  3189. // message d'erreur?
  3190. char* hts_errmsg(void) {
  3191.   return _hts_errmsg;
  3192. }
  3193. // mode pause transfer
  3194. HTSEXT_API int hts_setpause(int p) {
  3195.   if (p>=0) _hts_setpause=p;
  3196.   return _hts_setpause;
  3197. }
  3198. // ask for termination
  3199. HTSEXT_API int hts_request_stop(int force) {
  3200.   httrackp* opt=hts_declareoptbuffer(NULL);
  3201.   if (opt) {
  3202.     opt->state.stop=1;
  3203.   }
  3204.   return 0;
  3205. }
  3206. // rΘgler en cours de route les paramΦtres rΘglables..
  3207. // -1 : erreur
  3208. HTSEXT_API int hts_setopt(httrackp* set_opt) {
  3209.   if (set_opt) {
  3210.     httrackp* engine_opt=hts_declareoptbuffer(NULL);
  3211.     if (engine_opt) {
  3212.       //_hts_setopt=opt;
  3213.       copy_htsopt(set_opt,engine_opt);
  3214.     }
  3215.   }
  3216.   return 0;
  3217. }
  3218. // ajout d'URL
  3219. // -1 : erreur
  3220. HTSEXT_API int hts_addurl(char** url) {
  3221.   if (url) _hts_addurl=url;
  3222.   return (_hts_addurl!=NULL);
  3223. }
  3224. HTSEXT_API int hts_resetaddurl(void) {
  3225.   _hts_addurl=NULL;
  3226.   return (_hts_addurl!=NULL);
  3227. }
  3228. // copier nouveaux paramΦtres si besoin
  3229. HTSEXT_API int copy_htsopt(httrackp* from,httrackp* to) {
  3230.   if (from->maxsite > -1) 
  3231.     to->maxsite = from->maxsite;
  3232.   
  3233.   if (from->maxfile_nonhtml > -1) 
  3234.     to->maxfile_nonhtml = from->maxfile_nonhtml;
  3235.   
  3236.   if (from->maxfile_html > -1) 
  3237.     to->maxfile_html = from->maxfile_html;
  3238.   
  3239.   if (from->maxsoc > 0) 
  3240.     to->maxsoc = from->maxsoc;
  3241.   
  3242.   if (from->nearlink > -1) 
  3243.     to->nearlink = from->nearlink;
  3244.   
  3245.   if (from->timeout > -1) 
  3246.     to->timeout = from->timeout;
  3247.   
  3248.   if (from->rateout > -1)
  3249.     to->rateout = from->rateout;
  3250.   
  3251.   if (from->maxtime > -1) 
  3252.     to->maxtime = from->maxtime;
  3253.   
  3254.   if (from->maxrate > -1)
  3255.     to->maxrate = from->maxrate;
  3256.   
  3257.   if (strnotempty(from->user_agent)) 
  3258.     strcpybuff(to->user_agent , from->user_agent);
  3259.   
  3260.   if (from->retry > -1) 
  3261.     to->retry = from->retry;
  3262.   
  3263.   if (from->hostcontrol > -1) 
  3264.     to->hostcontrol = from->hostcontrol;
  3265.   
  3266.   if (from->errpage > -1) 
  3267.     to->errpage = from->errpage;
  3268.  
  3269.   if (from->parseall > -1) 
  3270.     to->parseall = from->parseall;
  3271.  
  3272.  
  3273.   // test all: bit 8 de travel
  3274.   if (from->travel > -1)  {
  3275.     if (from->travel & 256)
  3276.       to->travel|=256;
  3277.     else
  3278.       to->travel&=255;
  3279.   }
  3280.  
  3281.  
  3282.   return 0;
  3283. }
  3284.  
  3285. #endif
  3286. //
  3287.  
  3288. /* External modules callback */
  3289. int htsAddLink(htsmoduleStruct* str, char* link) {
  3290.   if (link != NULL && str != NULL && link[0] != '\0') {
  3291.     lien_url** liens = (lien_url**) str->liens;
  3292.     httrackp* opt = (httrackp*) str->opt;
  3293.     lien_back* back = (lien_back*) str->back;
  3294.     cache_back* cache = (cache_back*) str->cache;
  3295.     hash_struct* hashptr = (hash_struct*) str->hashptr;
  3296.     int back_max = str->back_max;
  3297.     int numero_passe = str->numero_passe;
  3298.     int add_tab_alloc = str->add_tab_alloc;
  3299.     /* */
  3300.     int lien_tot = * ( (int*) (str->lien_tot_) );
  3301.     int ptr = * ( (int*) (str->ptr_) );
  3302.     int lien_size = * ( (int*) (str->lien_size_) );
  3303.     char* lien_buffer = * ( (char**) (str->lien_buffer_) );
  3304.     /* */
  3305.     /* */
  3306.     char adr[HTS_URLMAXSIZE*2],
  3307.       fil[HTS_URLMAXSIZE*2],
  3308.       save[HTS_URLMAXSIZE*2];
  3309.     char codebase[HTS_URLMAXSIZE*2];
  3310.     /* */
  3311.     int pass_fix, prio_fix;
  3312.     /* */
  3313.     int forbidden_url = 1;
  3314.     
  3315.     codebase[0]='\0';
  3316.     
  3317.     if ((opt->debug>1) && (opt->log!=NULL)) {
  3318.       fspc(opt->log,"debug"); fprintf(opt->log,"(module): adding link : '%s'"LF, link); test_flush;
  3319.     }
  3320.     // recopie de "creer le lien"
  3321.     //    
  3322.  
  3323. #if HTS_ANALYSTE
  3324.   if (!hts_htmlcheck_linkdetected(link)) {
  3325.     if (opt->errlog) {
  3326.       fspc(opt->errlog,"error"); fprintf(opt->errlog,"Link %s refused by external wrapper"LF, link);
  3327.       test_flush;
  3328.     }
  3329.     return 0;
  3330.   }
  3331. #endif
  3332.  
  3333.     // adr = c'est la mΩme
  3334.     // fil et save: save2 et fil2
  3335.     prio_fix=maximum(liens[ptr]->depth-1,0);
  3336.     pass_fix=max(liens[ptr]->pass2,numero_passe);
  3337.     if (liens[ptr]->cod) strcpybuff(codebase,liens[ptr]->cod);       // codebase valable pour tt les classes descendantes
  3338.     if (strnotempty(codebase)==0) {    // pas de codebase, construire
  3339.       char* a;
  3340.       if (str->relativeToHtmlLink == 0)
  3341.         strcpybuff(codebase,liens[ptr]->fil);
  3342.       else
  3343.         strcpybuff(codebase,liens[liens[ptr]->precedent]->fil);
  3344.       a=codebase+strlen(codebase)-1;
  3345.       while((*a) && (*a!='/') && ( a > codebase)) a--;
  3346.       if (*a=='/')
  3347.         *(a+1)='\0';    // couper
  3348.     } else {    // couper http:// Θventuel
  3349.       if (strfield(codebase,"http://")) {
  3350.         char tempo[HTS_URLMAXSIZE*2];
  3351.         char* a=codebase+7;
  3352.         a=strchr(a,'/');    // aprΦs host
  3353.         if (a) {  // ** msg erreur et vΘrifier?
  3354.           strcpybuff(tempo,a);
  3355.           strcpybuff(codebase,tempo);    // couper host
  3356.         } else {
  3357.           if (opt->errlog) {   
  3358.             fprintf(opt->errlog,"Unexpected strstr error in base %s"LF,codebase);
  3359.             test_flush;
  3360.           }
  3361.         }
  3362.       }
  3363.     }
  3364.     
  3365.     if (!((int) strlen(codebase)<HTS_URLMAXSIZE)) {    // trop long
  3366.       if (opt->errlog) {   
  3367.         fprintf(opt->errlog,"Codebase too long, parsing skipped (%s)"LF,codebase);
  3368.         test_flush;
  3369.       }
  3370.     }
  3371.     
  3372.     {
  3373.       char* lien = link;
  3374.       int dejafait=0;
  3375.       
  3376.       if (strnotempty(lien) && strlen(lien) < HTS_URLMAXSIZE) {
  3377.         
  3378.         // calculer les chemins et noms de sauvegarde
  3379.         if (ident_url_relatif(lien,urladr,codebase,adr,fil)>=0) { // reformage selon chemin
  3380.           int r;
  3381.           int set_prio_to = 0;
  3382.           int just_test_it = 0;
  3383.           forbidden_url = hts_acceptlink(opt, ptr, lien_tot, liens,
  3384.             adr,fil,
  3385.             &set_prio_to,
  3386.             &just_test_it);
  3387.           if ((opt->debug>1) && (opt->log!=NULL)) {
  3388.             fspc(opt->log,"debug"); fprintf(opt->log,"result for wizard external module link: %d"LF,forbidden_url);
  3389.             test_flush;
  3390.           }
  3391.  
  3392.           /* Link accepted */
  3393.           if (!forbidden_url) {
  3394.             char tempo[HTS_URLMAXSIZE*2];
  3395.             int a,b;
  3396.             tempo[0]='\0';
  3397.             a=opt->savename_type;
  3398.             b=opt->savename_83;
  3399.             opt->savename_type=0;
  3400.             opt->savename_83=0;
  3401.             // note: adr,fil peuvent Ωtre patchΘs
  3402.             r=url_savename(adr,fil,save,NULL,NULL,NULL,NULL,opt,liens,lien_tot,back,back_max,cache,hashptr,ptr,numero_passe);
  3403.             opt->savename_type=a;
  3404.             opt->savename_83=b;
  3405.             if (r != -1) {
  3406.               if (savename) {
  3407.                 if (lienrelatif(tempo,save,savename)==0) {
  3408.                   if ((opt->debug>1) && (opt->log!=NULL)) {
  3409.                     fspc(opt->log,"debug"); fprintf(opt->log,"(module): relative link at %s build with %s and %s: %s"LF,adr,save,savename,tempo);
  3410.                     test_flush;
  3411.                     if (str->localLink && str->localLinkSize > (int) strlen(tempo) + 1) {
  3412.                       strcpybuff(str->localLink, tempo);
  3413.                     }
  3414.                   }
  3415.                 }
  3416.               }
  3417.             }
  3418.           } else {
  3419.             if ((opt->debug>1) && (opt->log!=NULL)) {
  3420.               fspc(opt->log,"debug"); fprintf(opt->log,"(module): file not caught: %s"LF,lien); test_flush;
  3421.             }
  3422.             if (str->localLink && str->localLinkSize > (int) ( strlen(adr) + strlen(fil) +  8 ) ) {
  3423.               str->localLink[0] = '\0';
  3424.               if (!link_has_authority(adr))
  3425.                 strcpybuff(str->localLink,"http://");
  3426.               strcatbuff(str->localLink, adr);
  3427.               strcatbuff(str->localLink, fil);
  3428.             }
  3429.             r=-1;
  3430.           }
  3431.           //
  3432.           if (r != -1) {
  3433.             if ((opt->debug>1) && (opt->log!=NULL)) {
  3434.               fspc(opt->log,"debug"); fprintf(opt->log,"(module): %s%s -> %s (base %s)"LF,adr,fil,save,codebase); test_flush;
  3435.             }
  3436.             
  3437.             // modifiΘ par rapport α l'autre version (cf prio_fix notamment et save2)
  3438.             
  3439.             // vΘrifier que le lien n'a pas dΘja ΘtΘ notΘ
  3440.             // si c'est le cas, alors il faut s'assurer que la prioritΘ associΘe
  3441.             // au fichier est la plus grande des deux prioritΘs
  3442.             //
  3443.             // On part de la fin et on essaye de se presser (Θconomise temps machine)
  3444. #if HTS_HASH
  3445.             {
  3446.               int i=hash_read(hashptr,save,"",0,opt->urlhack);      // lecture type 0 (sav)
  3447.               if (i>=0) {
  3448.                 liens[i]->depth=maximum(liens[i]->depth,prio_fix);
  3449.                 dejafait=1;
  3450.               }
  3451.             }
  3452. #else
  3453.             {
  3454.               int l;
  3455.               int i;
  3456.               l=strlen(save);
  3457.               for(i=lien_tot-1;(i>=0) && (dejafait==0);i--) {
  3458.                 if (liens[i]->sav_len==l) {    // mΩme taille de chaεne
  3459.                   if (strcmp(liens[i]->sav,save)==0) {    // existe dΘja
  3460.                     liens[i]->depth=maximum(liens[i]->depth,prio_fix);
  3461.                     dejafait=1;
  3462.                   }
  3463.                 }
  3464.               }
  3465.             }
  3466. #endif
  3467.             
  3468.             
  3469.             if (!dejafait) {
  3470.               //
  3471.               // >>>> CREER LE LIEN JAVA <<<<
  3472.               
  3473.               // enregistrer fichier (MACRO)
  3474.               liens_record(adr,fil,save,"","",opt->urlhack);
  3475.               if (liens[lien_tot]==NULL) {  // erreur, pas de place rΘservΘe
  3476.                 printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  3477.                 if (opt->errlog) { 
  3478.                   fprintf(opt->errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  3479.                   test_flush;
  3480.                 }
  3481.                 exit_xh=-1;    /* fatal error -> exit */
  3482.                 return 0;
  3483.               }  
  3484.               
  3485.               // mode test?                          
  3486.               liens[lien_tot]->testmode=0;          // pas mode test
  3487.               
  3488.               liens[lien_tot]->link_import=0;       // pas mode import
  3489.               
  3490.               // Θcrire autres paramΦtres de la structure-lien
  3491.               //if (meme_adresse)                                 
  3492.               liens[lien_tot]->premier=liens[ptr]->premier;
  3493.               //else    // sinon l'objet pΦre est le prΘcΘdent lui mΩme
  3494.               //  liens[lien_tot]->premier=ptr;
  3495.               
  3496.               liens[lien_tot]->precedent=ptr;
  3497.               // noter la prioritΘ
  3498.               if (!set_prio_to)
  3499.                 liens[lien_tot]->depth=prio_fix;
  3500.               else
  3501.                 liens[lien_tot]->depth=max(0,min(liens[ptr]->depth-1,set_prio_to-1));         // PRIORITE NULLE (catch page)
  3502.               liens[lien_tot]->pass2=max(pass_fix,numero_passe);
  3503.               liens[lien_tot]->retry=opt->retry;
  3504.               
  3505.               //strcpybuff(liens[lien_tot]->adr,adr);
  3506.               //strcpybuff(liens[lien_tot]->fil,fil);
  3507.               //strcpybuff(liens[lien_tot]->sav,save); 
  3508.               if ((opt->debug>1) && (opt->log!=NULL)) {
  3509.                 fspc(opt->log,"debug"); fprintf(opt->log,"(module): OK, NOTE: %s%s -> %s"LF,liens[lien_tot]->adr,liens[lien_tot]->fil,liens[lien_tot]->sav);
  3510.                 test_flush;
  3511.               }
  3512.               
  3513.               lien_tot++;  // UN LIEN DE PLUS
  3514.             }
  3515.           }
  3516.         }
  3517.       }
  3518.     }
  3519.     
  3520.     /* Apply changes */
  3521.     * ( (int*) (str->lien_tot_) ) = lien_tot;
  3522.     * ( (int*) (str->ptr_) ) = ptr;
  3523.     * ( (int*) (str->lien_size_) ) = lien_size;
  3524.     * ( (char**) (str->lien_buffer_) ) = lien_buffer;
  3525.     return (forbidden_url == 0);
  3526.   }
  3527.   return 0;
  3528. }
  3529.  
  3530.  
  3531.  
  3532.  
  3533.  
  3534. // message copyright interne
  3535. void voidf(void) {
  3536.   char* a;
  3537.   a=""CRLF""CRLF;
  3538.   a="+-----------------------------------------------+"CRLF;
  3539.   a="|HyperTextTRACKer, Offline Browser Utility      |"CRLF;
  3540.   a="|                      HTTrack Website Copier   |"CRLF;
  3541.   a="|Code:         Windows Interface Xavier Roche   |"CRLF;
  3542.   a="|                    HTS/HTTrack Xavier Roche   |"CRLF;
  3543.   a="|                .class Parser Yann Philippot   |"CRLF;
  3544.   a="|                                               |"CRLF;
  3545.   a="|Tested on:                 Windows95,98,NT,2K  |"CRLF;
  3546.   a="|                           Linux PC            |"CRLF;
  3547.   a="|                           Sun-Solaris 5.6     |"CRLF;
  3548.   a="|                           AIX 4               |"CRLF;
  3549.   a="|                                               |"CRLF;
  3550.   a="|Copyright (C) Xavier Roche and other           |"CRLF;
  3551.   a="|contributors                                   |"CRLF;
  3552.   a="|                                               |"CRLF;
  3553.   a="|Use this program at your own risks!            |"CRLF;    
  3554.   a="+-----------------------------------------------+"CRLF;
  3555.   a=""CRLF;
  3556. }
  3557.  
  3558.  
  3559. // HTTrack Website Copier Copyright (C) Xavier Roche and other contributors
  3560. //
  3561.  
  3562.